// Init create directory and setup the cache location func (ucc *UpdateClientConfig) Init() error { homeDir := os.Getenv("HOME") if homeDir == "" { return errors.New("Cannot get home directory") } topPath := filepath.Join(homeDir, topDir) if !utils.IsDirExist(topPath) { if err := os.MkdirAll(topPath, os.ModePerm); err != nil { return err } } cachePath := filepath.Join(homeDir, topDir, cacheDir) if !utils.IsDirExist(cachePath) { if err := os.MkdirAll(cachePath, os.ModePerm); err != nil { return err } } if !ucc.exist() { return ucc.save() } return nil }
func SaveLayerLocal(srcPath, srcFile, dstPath, dstFile string, reqbody []byte) (int, error) { if !utils.IsDirExist(dstPath) { os.MkdirAll(dstPath, os.ModePerm) } if utils.IsFileExist(dstFile) { os.Remove(dstFile) } var data []byte if _, err := os.Stat(srcFile); err == nil { data, _ = ioutil.ReadFile(srcFile) if err := ioutil.WriteFile(dstFile, data, 0777); err != nil { return 0, err } os.RemoveAll(srcPath) } else { data = reqbody if err := ioutil.WriteFile(dstFile, data, 0777); err != nil { return 0, err } } return len(data), nil }
func PutImageLayerv1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { imageId := ctx.Params(":imageId") basePath := setting.ImagePath imagePath := fmt.Sprintf("%v/images/%v", basePath, imageId) layerfile := fmt.Sprintf("%v/images/%v/layer", basePath, imageId) if !utils.IsDirExist(imagePath) { os.MkdirAll(imagePath, os.ModePerm) } if _, err := os.Stat(layerfile); err == nil { os.Remove(layerfile) } data, _ := ctx.Req.Body().Bytes() if err := ioutil.WriteFile(layerfile, data, 0777); err != nil { log.Error("[REGISTRY API V1] Failed to save image layer: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to save image layer"}) return http.StatusBadRequest, result } i := new(models.Image) if err := i.PutLayer(imageId, layerfile, true, int64(len(data))); err != nil { log.Error("[REGISTRY API V1] Failed to save image %v layer data: %v", imageId, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to save image layer data"}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
// SetKM sets the keymanager func (r *LocalRepo) SetKM(kmURL string) error { // pull the public key k, err := km.NewKeyManager(kmURL) if err != nil { return err } data, err := k.GetPublicKey(r.Proto, r.Namespace) if err != nil { return err } keyfile := r.GetPublicKeyFile() if !utils.IsDirExist(filepath.Dir(keyfile)) { if err := os.MkdirAll(filepath.Dir(keyfile), 0755); err != nil { return err } } if err := ioutil.WriteFile(keyfile, data, 0644); err != nil { return err } r.kmURL = kmURL return nil }
func (uc *UpdateClient) save(repo client.UpdateClientRepo, file string, bytes []byte) (string, error) { localFile := filepath.Join(uc.getCacheDir(), repo.NRString(), file) if !utils.IsDirExist(filepath.Dir(localFile)) { os.MkdirAll(filepath.Dir(localFile), 0755) } err := ioutil.WriteFile(localFile, bytes, 0644) if err != nil { return "", err } return localFile, nil }
//PatchBlobsV2Handler is //Upload a chunk of data for the specified upload. //Docker 1.9.x above version saves layer in PATCH methord //Docker 1.9.x below version saves layer in PUT methord func PatchBlobsV2Handler(ctx *macaron.Context) (int, []byte) { repository := ctx.Params(":repository") namespace := ctx.Params(":namespace") desc := ctx.Params(":uuid") uuid := strings.Split(desc, "?")[0] if upload, err := module.CheckDockerVersion19(ctx.Req.Header.Get("User-Agent")); err != nil { log.Errorf("Decode docker version error: %s", err.Error()) result, _ := module.EncodingError(module.BLOB_UPLOAD_UNKNOWN, map[string]string{"namespace": namespace, "repository": repository}) return http.StatusBadRequest, result } else if upload == true { //It's run above docker 1.9.0 basePath := setting.DockerV2Storage uuidPath := fmt.Sprintf("%s/uuid/%s", basePath, uuid) uuidFile := fmt.Sprintf("%s/uuid/%s/%s", basePath, uuid, uuid) if !utils.IsDirExist(uuidPath) { os.MkdirAll(uuidPath, os.ModePerm) } if _, err := os.Stat(uuidFile); err == nil { os.Remove(uuidFile) } if file, err := os.Create(uuidFile); err != nil { log.Errorf("[%s] Create UUID file error: %s", ctx.Req.RequestURI, err.Error()) result, _ := module.EncodingError(module.BLOB_UPLOAD_UNKNOWN, map[string]string{"namespace": namespace, "repository": repository}) return http.StatusBadRequest, result } else { io.Copy(file, ctx.Req.Request.Body) size, _ := utils.GetFileSize(uuidFile) ctx.Resp.Header().Set("Range", fmt.Sprintf("0-%v", size-1)) } } state := utils.MD5(fmt.Sprintf("%s/%v", fmt.Sprintf("%s/%s", namespace, repository), time.Now().UnixNano()/int64(time.Millisecond))) random := fmt.Sprintf("https://%s/v2/%s/%s/blobs/uploads/%s?_state=%s", setting.Domains, namespace, repository, uuid, state) ctx.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8") ctx.Resp.Header().Set("Docker-Upload-Uuid", uuid) ctx.Resp.Header().Set("Location", random) result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
//AppcPutACIV1Handler is func AppcPutACIV1Handler(ctx *macaron.Context) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") version := ctx.Params(":version") aci := ctx.Params(":aci") r := new(models.AppcV1) if err := r.Get(namespace, repository); err != nil { log.Errorf("[%s] get AppcV1 repository error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Get Appc Repository Error."}) return http.StatusBadRequest, result } basePath := setting.AppcStorage imagePath := fmt.Sprintf("%s/%s/%s/%s", basePath, namespace, repository, version) filePath := fmt.Sprintf("%s/%s", imagePath, aci) if !utils.IsDirExist(imagePath) { os.MkdirAll(imagePath, os.ModePerm) } if _, err := os.Stat(filePath); err == nil { os.Remove(filePath) } if file, err := os.Create(filePath); err != nil { log.Errorf("[%s] Create aci file error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Create .aci File Error."}) return http.StatusBadRequest, result } else { io.Copy(file, ctx.Req.Request.Body) } size, _ := utils.GetFileSize(filePath) i := new(models.ACIv1) if err := i.PutACI(r.ID, size, version, aci, filePath); err != nil { log.Errorf("[%s] write aci data error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Write .aci Data Error."}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func PatchBlobsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") desc := ctx.Params(":uuid") uuid := strings.Split(desc, "?")[0] imagePathTmp := module.GetImagePath(uuid, setting.APIVERSION_V2) layerPathTmp := module.GetLayerPath(uuid, "layer", setting.APIVERSION_V2) //saving specific tarsum every times is in order to split the same tarsum in HEAD handler if !utils.IsDirExist(imagePathTmp) { os.MkdirAll(imagePathTmp, os.ModePerm) } if _, err := os.Stat(layerPathTmp); err == nil { os.Remove(layerPathTmp) } data, _ := ctx.Req.Body().Bytes() if err := ioutil.WriteFile(layerPathTmp, data, 0777); err != nil { log.Error("[REGISTRY API V2] Failed to save layer %v: %v", layerPathTmp, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to save layer file"}) return http.StatusInternalServerError, result } state := utils.MD5(fmt.Sprintf("%s/%s/%d", namespace, repository, time.Now().UnixNano()/int64(time.Millisecond))) random := fmt.Sprintf("%s://%s/v2/%s/%s/blobs/uploads/%s?_state=%s", setting.ListenMode, setting.Domains, namespace, repository, uuid, state) ctx.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8") ctx.Resp.Header().Set("Docker-Upload-Uuid", uuid) ctx.Resp.Header().Set("Location", random) ctx.Resp.Header().Set("Range", fmt.Sprintf("0-%v", len(data)-1)) result, _ := json.Marshal(map[string]string{}) return http.StatusAccepted, result }
//PutImageLayerV1Handler is save image layer file in the server. func PutImageLayerV1Handler(ctx *macaron.Context) (int, []byte) { //TODO: If standalone == true, Dockyard will check HEADER Authorization; if standalone == false, Dockyard will check HEADER TOEKN. imageID := ctx.Params(":image") basePath := setting.DockerV1Storage imagePath := fmt.Sprintf("%s/images/%s", basePath, imageID) layerfile := fmt.Sprintf("%s/images/%s/%s", basePath, imageID, imageID) if !utils.IsDirExist(imagePath) { os.MkdirAll(imagePath, os.ModePerm) } if _, err := os.Stat(layerfile); err == nil { os.Remove(layerfile) } if file, err := os.Create(layerfile); err != nil { log.Errorf("[%s] Create image file error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Write Image File Error."}) return http.StatusBadRequest, result } else { io.Copy(file, ctx.Req.Request.Body) } size, _ := utils.GetFileSize(layerfile) image := new(models.DockerImageV1) if err := image.PutLayer(imageID, layerfile, size); err != nil { log.Errorf("[%s] Failed to save image layer data error: %s", ctx.Req.RequestURI, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put Image Layer Data Error"}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func generateKey(keyDir string) error { privBytes, pubBytes, err := utils.GenerateRSAKeyPair(defaultBitsSize) if err != nil { return err } if !utils.IsDirExist(keyDir) { err := os.MkdirAll(keyDir, 0755) if err != nil { return err } } if err := ioutil.WriteFile(filepath.Join(keyDir, defaultPrivateKey), privBytes, 0600); err != nil { return err } if err := ioutil.WriteFile(filepath.Join(keyDir, defaultPublicKey), pubBytes, 0644); err != nil { return err } return nil }
// NewLocalRepo gets repo by a proto, a local storage path and a url // nr : "namespace/repository" or just 'namespace' func NewLocalRepo(path string, proto string, nr string) (LocalRepo, error) { repo := LocalRepo{Proto: proto, Path: path} parts := strings.Split(nr, "/") if nr != "" && len(parts) == 1 { repo.Namespace = nr } else if len(parts) == 2 { repo.Namespace = parts[0] repo.LocalRepository = parts[1] } else { return LocalRepo{}, ErrorInvalidLocalLocalRepo } // create top dir if not exist topDir := repo.GetTopDir() if !utils.IsDirExist(topDir) { if err := os.MkdirAll(topDir, 0777); err != nil { return LocalRepo{}, err } } repo.kmURL = "" return repo, nil }
//PutBlobsV2Handler is //Complete the upload specified by uuid, optionally appending the body as the final chunk. func PutBlobsV2Handler(ctx *macaron.Context) (int, []byte) { var size int64 repository := ctx.Params(":repository") namespace := ctx.Params(":namespace") desc := ctx.Params(":uuid") uuid := strings.Split(desc, "?")[0] digest := ctx.Query("digest") tarsum := strings.Split(digest, ":")[1] basePath := setting.DockerV2Storage imagePath := fmt.Sprintf("%s/image/%s", basePath, tarsum) imageFile := fmt.Sprintf("%s/image/%s/%s", basePath, tarsum, tarsum) //Save from uuid path save too image path if !utils.IsDirExist(imagePath) { os.MkdirAll(imagePath, os.ModePerm) } if _, err := os.Stat(imageFile); err == nil { os.Remove(imageFile) } if upload, err := module.CheckDockerVersion19(ctx.Req.Header.Get("User-Agent")); err != nil { log.Errorf("Decode docker version error: %s", err.Error()) result, _ := module.EncodingError(module.BLOB_UPLOAD_INVALID, map[string]string{"namespace": namespace, "repository": repository}) return http.StatusBadRequest, result } else if upload == true { //Docker 1.9.x above version saves layer in PATCH method, in PUT method move from uuid to image:sha256 uuidPath := fmt.Sprintf("%s/uuid/%s", basePath, uuid) uuidFile := fmt.Sprintf("%s/uuid/%s/%s", basePath, uuid, uuid) if _, err := os.Stat(uuidFile); err == nil { if err := os.Rename(uuidFile, imageFile); err != nil { log.Errorf("Move the temp file to image folder %s error: %s", imageFile, err.Error()) result, _ := module.EncodingError(module.BLOB_UPLOAD_INVALID, map[string]string{"namespace": namespace, "repository": repository}) return http.StatusBadRequest, result } size, _ = utils.GetFileSize(imagePath) os.RemoveAll(uuidFile) os.RemoveAll(uuidPath) } } else if upload == false { //Docker 1.9.x below version saves layer in PUT methord, save data to file directly. if file, err := os.Create(imageFile); err != nil { log.Errorf("Save the file %s error: %s", imageFile, err.Error()) result, _ := module.EncodingError(module.BLOB_UPLOAD_INVALID, map[string]string{"namespace": namespace, "repository": repository}) return http.StatusBadRequest, result } else { io.Copy(file, ctx.Req.Request.Body) size, _ = utils.GetFileSize(imagePath) } } i := new(models.DockerImageV2) if err := i.Put(tarsum, imageFile, size); err != nil { log.Errorf("Save the iamge data %s error: %s", tarsum, err.Error()) result, _ := module.EncodingError(module.BLOB_UPLOAD_INVALID, map[string]string{"namespace": namespace, "repository": repository}) return http.StatusBadRequest, result } state := utils.MD5(fmt.Sprintf("%s/%v", fmt.Sprintf("%s/%s", namespace, repository), time.Now().UnixNano()/int64(time.Millisecond))) random := fmt.Sprintf("https://%s/v2/%s/%s/blobs/uploads/%s?_state=%s", setting.Domains, namespace, repository, uuid, state) ctx.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8") ctx.Resp.Header().Set("Docker-Content-Digest", digest) ctx.Resp.Header().Set("Location", random) result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
// Put adds an application to a repository func (r LocalRepo) Put(name string, content []byte, method utils.EncryptMethod) (string, error) { topDir := r.GetTopDir() if !utils.IsDirExist(topDir) { if err := os.MkdirAll(topDir, 0777); err != nil { return "", err } } var meta utils.Meta metaFile := r.GetMetaFile() if utils.IsFileExist(metaFile) { data, err := ioutil.ReadFile(metaFile) if err != nil { return "", err } err = json.Unmarshal(data, &meta) if err != nil { //This may happend in migration, meta struct changes. os.Remove(metaFile) } } encryptContent, err := r.encrypt(method, content) if err != nil { return "", err } item := utils.GenerateMetaItem(name, encryptContent) item.SetEncryption(method) // Using the 'hash' value to rename the original file dataFileName := item.GetHash() dataFile := filepath.Join(topDir, defaultTargetDir, dataFileName) if !utils.IsDirExist(filepath.Dir(dataFile)) { if err := os.MkdirAll(filepath.Dir(dataFile), 0777); err != nil { return "", err } } // write data if err := ioutil.WriteFile(dataFile, encryptContent, 0644); err != nil { return "", err } // get meta content exist := false for i := range meta.Items { if meta.Items[i].Name == name { meta.Items[i] = item exist = true } } if !exist { meta.Items = append(meta.Items, item) } // write meta data err = r.saveMeta(meta) if err != nil { os.Remove(dataFile) return "", err } return dataFile, nil }