func GetTagsListV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") r := new(models.Repository) if _, err := r.Get(namespace, repository); err != nil { log.Error("[REGISTRY API V2] Failed to get repository %v/%v: %v", namespace, repository, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to get repository"}) return http.StatusBadRequest, result } data := map[string]interface{}{} data["name"] = fmt.Sprintf("%s/%s", namespace, repository) tagslist := r.GetTagslist() if len(tagslist) <= 0 { log.Error("[REGISTRY API V2] Repository %v/%v tags list is empty", namespace, repository) result, _ := json.Marshal(map[string]string{"message": "Tags list is empty"}) return http.StatusNotFound, result } data["tags"] = tagslist result, _ := json.Marshal(data) return http.StatusOK, result }
func GetTagsListV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") r := new(models.Repository) if has, _, err := r.Has(namespace, repository); err != nil || has == false { log.Error("[REGISTRY API V2] Repository not found: %v", repository) result, _ := json.Marshal(map[string]string{"message": "Repository not found"}) return http.StatusNotFound, result } data := map[string]interface{}{} tags := []string{} data["name"] = fmt.Sprintf("%s/%s", namespace, repository) for _, value := range r.Tags { t := new(models.Tag) if err := t.GetByKey(value); err != nil { log.Error("[REGISTRY API V2] Tag not found: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Tag not found"}) return http.StatusNotFound, result } tags = append(tags, t.Name) } data["tags"] = tags result, _ := json.Marshal(data) return http.StatusOK, result }
// TBD: discovery template should be updated to keep in line with ACI func DiscoveryACIHandler(ctx *macaron.Context, log *logs.BeeLogger) { img := ctx.Params(":imagename") t, err := template.ParseFiles("conf/acifetchtemplate.html") if err != nil { log.Error("[ACI API] Discovery parse template file failed: %v", err.Error()) ctx.Resp.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(ctx.Resp, fmt.Sprintf("%v", err)) return } err = t.Execute(ctx.Resp, struct { Name string ServerName string ListenMode string }{ Name: img, ServerName: setting.Domains, ListenMode: setting.ListenMode, }) if err != nil { log.Error("[ACI API] Discovery respond failed: %v", err.Error()) fmt.Fprintf(ctx.Resp, fmt.Sprintf("%v", err)) } }
func HeadBlobsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { digest := ctx.Params(":digest") tarsum := strings.Split(digest, ":")[1] ctx.Resp.Header().Set("Content-Type", "application/json; charset=utf-8") i := new(models.Image) if exists, err := i.Get(tarsum); err != nil { log.Info("[REGISTRY API V2] Failed to get tarsum %v: %v", tarsum, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to get tarsum"}) return http.StatusBadRequest, result } else if !exists { log.Info("[REGISTRY API V2] Not found tarsum: %v", tarsum) result, _ := json.Marshal(map[string]string{"message": "Not found tarsum"}) return http.StatusNotFound, result } ctx.Resp.Header().Set("Content-Type", "application/octet-stream") ctx.Resp.Header().Set("Docker-Content-Digest", digest) ctx.Resp.Header().Set("Content-Length", fmt.Sprint(i.Size)) result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
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, _ := ioutil.ReadAll(ctx.Req.Request.Body) if err := ioutil.WriteFile(layerfile, data, 0777); err != nil { log.Error("[REGISTRY API V1] Put Image Layer File Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put Image Layer File Error"}) 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] Put Image Layer File Data Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put Image Layer File Data Error"}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func GetImageJSONV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { var jsonInfo string var payload string var err error imageId := ctx.Params(":imageId") i := new(models.Image) if jsonInfo, err = i.GetJSON(imageId); err != nil { log.Error("[REGISTRY API V1] Search Image JSON Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Search Image JSON Error"}) return http.StatusNotFound, result } if payload, err = i.GetChecksumPayload(imageId); err != nil { log.Error("[REGISTRY API V1] Search Image Checksum Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Search Image Checksum Error"}) return http.StatusNotFound, result } ctx.Resp.Header().Set("X-Docker-Checksum-Payload", fmt.Sprintf("sha256:%v", payload)) ctx.Resp.Header().Set("X-Docker-Size", fmt.Sprint(i.Size)) ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(jsonInfo))) return http.StatusOK, []byte(jsonInfo) }
func GetManifestsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") tag := ctx.Params(":tag") t := new(models.Tag) if exists, err := t.Get(namespace, repository, tag); err != nil || !exists { log.Error("[REGISTRY API V2] Not found manifest: %v", err) result, _ := json.Marshal(map[string]string{"message": "Not found manifest"}) return http.StatusNotFound, result } digest, err := signature.DigestManifest([]byte(t.Manifest)) if err != nil { log.Error("[REGISTRY API V2] Failed to get manifest digest: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to get manifest digest"}) return http.StatusInternalServerError, result } contenttype := []string{"", "application/json; charset=utf-8", "application/vnd.docker.distribution.manifest.v2+json"} ctx.Resp.Header().Set("Content-Type", contenttype[t.Schema]) ctx.Resp.Header().Set("Docker-Content-Digest", digest) ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(t.Manifest))) return http.StatusOK, []byte(t.Manifest) }
func InitiateUpload(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { image := ctx.Params(":image") if image == "" { log.Error("[ACI API]Get image name failed") result, _ := json.Marshal(map[string]string{"message": "Get image name failed"}) return http.StatusNotFound, result } uploadNum := strconv.Itoa(newUpload(image)) var prefix string prefix = setting.ListenMode + "://" + setting.Domains + "/ac-push" deets := initiateDetails{ ACIPushVersion: "0.0.1", Multipart: false, ManifestURL: prefix + "/manifest/" + uploadNum, SignatureURL: prefix + "/signature/" + uploadNum, ACIURL: prefix + "/aci/" + uploadNum, CompletedURL: prefix + "/complete/" + uploadNum, } result, _ := json.Marshal(deets) return http.StatusInternalServerError, result }
func GetFileInfo(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { path := ctx.Req.Header.Get(headerPath) log.Info("[OSS][getFileInfo] Path: %s", path) result, err := metaDriver.GetFileMetaInfo(path, false) if err != nil { log.Error("[OSS][getFileInfo] get metainfo error, key: %s, error: %s", path, err) return http.StatusInternalServerError, []byte(err.Error()) } if len(result) == 0 { log.Info("[OSS][getFileInfo] metainfo not exists, key: %s", path) return http.StatusNotFound, []byte(err.Error()) } resultMap := make(map[string]interface{}) resultMap["fragment-info"] = result jsonResult, err := json.Marshal(resultMap) if err != nil { log.Error("json.Marshal error, key: %s, error: %s", path, err) return http.StatusInternalServerError, []byte(err.Error()) } log.Info("[getFileInfo] success, path: %s, result: %s", path, string(jsonResult)) return http.StatusOK, jsonResult }
func UploadFile(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { metaInfo, _, err := uploadFileReadParam(&ctx.Req.Header) if err != nil { log.Error("[OSS][uploadFile] read param error: %v", err) return http.StatusBadRequest, []byte(err.Error()) } data, err := ctx.Req.Body().Bytes() if err != nil { log.Error("[OSS]read request body error: %s", err) return http.StatusBadRequest, []byte(err.Error()) } statusCode, err := ossupload(data, metaInfo) if err != nil { log.Error("[OSS][uploadFile] upload error: %v", err) return statusCode, []byte(err.Error()) } if err = metaDriver.StoreMetaInfoV1(metaInfo); err != nil { log.Error("[OSS]store metaInfo error: %s", err) return http.StatusInternalServerError, []byte(err.Error()) } log.Info("[OSS][postFile] success. path: %s, fragmentIndex: %d, bytesRange: %d-%d, isLast: %v", metaInfo.Path, metaInfo.Value.Index, metaInfo.Value.Start, metaInfo.Value.End, metaInfo.Value.IsLast) return http.StatusOK, nil }
func GetManifestsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { t := new(models.Tag) namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") if err := t.Get(namespace, repository, ctx.Params(":tag")); err != nil { log.Error("[REGISTRY API V2] Manifest not found: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Manifest not found"}) return http.StatusNotFound, result } digest, err := utils.DigestManifest([]byte(t.Manifest)) if err != nil { log.Error("[REGISTRY API V2] Get manifest digest failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Get manifest digest failed"}) return http.StatusBadRequest, result } ctx.Resp.Header().Set("Content-Type", "application/json; charset=utf-8") ctx.Resp.Header().Set("Docker-Content-Digest", digest) ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(t.Manifest))) return http.StatusOK, []byte(t.Manifest) }
func PutRepositoryImagesV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") r := new(models.Repository) if err := r.PutImages(namespace, repository); err != nil { log.Error("[REGISTRY API V1] Put images error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put V1 images error"}) return http.StatusBadRequest, result } if ctx.Req.Header.Get("X-Docker-Token") == "true" { username, _, _ := utils.DecodeBasicAuth(ctx.Req.Header.Get("Authorization")) token := fmt.Sprintf("Token signature=%v,repository=\"%v/%v\",access=%v", utils.MD5(username), namespace, repository, "write") ctx.Resp.Header().Set("X-Docker-Token", token) ctx.Resp.Header().Set("WWW-Authenticate", token) } result, _ := json.Marshal(map[string]string{}) return http.StatusNoContent, result }
func PutRepositoryV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { username, _, _ := utils.DecodeBasicAuth(ctx.Req.Header.Get("Authorization")) namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") body, err := ctx.Req.Body().String() if err != nil { log.Error("[REGISTRY API V1] Get request body error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put V1 repository failed,request body is empty"}) return http.StatusBadRequest, result } r := new(models.Repository) if err := r.Put(namespace, repository, body, ctx.Req.Header.Get("User-Agent"), setting.APIVERSION_V1); err != nil { log.Error("[REGISTRY API V1] Put repository error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": err.Error()}) return http.StatusBadRequest, result } if ctx.Req.Header.Get("X-Docker-Token") == "true" { token := fmt.Sprintf("Token signature=%v,repository=\"%v/%v\",access=%v", utils.MD5(username), namespace, repository, "write") ctx.Resp.Header().Set("X-Docker-Token", token) ctx.Resp.Header().Set("WWW-Authenticate", token) } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func GetPubkeys(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { var pubkey []byte var err error pubkeypath := setting.ImagePath + "/acpool/" + "pubkeys.gpg" if pubkey, err = ioutil.ReadFile(pubkeypath); err != nil { log.Error("[ACI API] Get pubkey file failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Get pubkey file failed"}) return http.StatusNotFound, result } return http.StatusOK, pubkey }
// 初始化日志模块 func newLogger(config LogConfig, isDaily bool) (*logs.BeeLogger, error) { var logger *logs.BeeLogger var configInner logConfigInner if config.Filename == "" { return logger, errors.New("文件名不能为空哈") } configInner.Filename = config.Filename if config.Maxlines == 0 { config.Maxlines = 1000000 } configInner.Maxlines = config.Maxlines configInner.Daily = isDaily if config.Maxdays == 0 { config.Maxdays = 7 } configInner.Maxdays = config.Maxdays logLevel := map[string]int{ "error": logs.LevelError, "warn": logs.LevelWarning, "info": logs.LevelInformational, } var logLevelInt int if config.Level == "" { logLevelInt = logs.LevelInformational } else { var ok bool logLevelInt, ok = logLevel[config.Level] if ok == false { return logger, errors.New("日志等级设置不正确") } } configInner.Level = logLevelInt configInner.Rotate = true // 普通日志 logger = logs.NewLogger(10000) logConfigString, err := json.Marshal(&configInner) if err != nil { return logger, err } err = logger.SetLogger("file", string(logConfigString)) if err != nil { return logger, err } return logger, nil }
func ReceiveChunkserverInfo(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { header := ctx.Req.Header nodeip := header.Get("nodeip") nodeport := header.Get("nodeport") groupid := header.Get("groupid") stderr := header.Get("stderr") stdout := header.Get("stdout") log.Info("[OSS]Chunkserver %s:%s groupid:%s start error", nodeip, nodeport, groupid) log.Info("[OSS]STDOUT:%s", stdout) log.Info("[OSS]STDERR:%s", stderr) return http.StatusOK, []byte("information recieced") }
func ReceiveAciUpload(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { num, err := strconv.Atoi(ctx.Params(":num")) if err != nil { fmt.Fprintf(os.Stderr, "%v", err) result, _ := json.Marshal(map[string]string{}) return http.StatusNotFound, result } up := getUpload(num) if up == nil { fmt.Fprintf(os.Stderr, "%v", err) result, _ := json.Marshal(map[string]string{}) return http.StatusNotFound, result } _, err = os.Stat(up.Image) if err == nil { log.Error("[ACI API]item already uploaded") result, _ := json.Marshal(map[string]string{"message": "item already uploaded"}) return http.StatusConflict, result } else if !os.IsNotExist(err) { fmt.Fprintf(os.Stderr, "%v", err) result, _ := json.Marshal(map[string]string{}) return http.StatusInternalServerError, result } aci, err := os.OpenFile(tmpACIPath(num), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { fmt.Fprintf(os.Stderr, "%v", err) result, _ := json.Marshal(map[string]string{}) return http.StatusInternalServerError, result } defer aci.Close() _, err = io.Copy(aci, ctx.Req.Request.Body) if err != nil { fmt.Fprintf(os.Stderr, "%v", err) result, _ := json.Marshal(map[string]string{}) return http.StatusInternalServerError, result } err = gotACI(num) if err != nil { fmt.Fprintf(os.Stderr, "%v", err) result, _ := json.Marshal(map[string]string{}) return http.StatusInternalServerError, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func PutImageChecksumV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { imageId := ctx.Params(":imageId") checksum := strings.Split(ctx.Req.Header.Get("X-Docker-Checksum"), ":")[1] payload := strings.Split(ctx.Req.Header.Get("X-Docker-Checksum-Payload"), ":")[1] log.Debug("[REGISTRY API V1] Image Checksum : %v", checksum) log.Debug("[REGISTRY API V1] Image Payload: %v", payload) i := new(models.Image) if err := i.PutChecksum(imageId, checksum, true, payload); err != nil { log.Error("[REGISTRY API V1] Put Image Checksum & Payload Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put Image Checksum & Payload Error"}) return http.StatusBadRequest, result } if err := i.PutAncestry(imageId); err != nil { log.Error("[REGISTRY API V1] Put Image Ancestry Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put Image Ancestry Error"}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func GetImageAncestryV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { imageId := ctx.Params(":imageId") i := new(models.Image) if _, err := i.Get(imageId); err != nil { log.Error("[REGISTRY API V1] Failed to get image %v ancestry: %v", imageId, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to get image ancestry"}) return http.StatusBadRequest, result } ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(i.Ancestry))) return http.StatusOK, []byte(i.Ancestry) }
func PutManifestHandler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { imageId := ctx.Params(":imageId") manipath := module.GetManifestPath(imageId, setting.APIVERSION_ACI) data, _ := ctx.Req.Body().Bytes() if err := ioutil.WriteFile(manipath, data, 0777); err != nil { //Temporary directory would be deleted in PostCompleteHandler log.Error("[ACI API] Failed to save manifest file: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to save manifest"}) return http.StatusInternalServerError, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func PutAciHandler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { imageId := ctx.Params(":imageId") acifile := ctx.Params(":acifile") acipath := module.GetAciPath(imageId, acifile) data, _ := ctx.Req.Body().Bytes() if err := ioutil.WriteFile(acipath, data, 0777); err != nil { //Temporary directory would be deleted in PostCompleteHandler log.Error("[ACI API] Save aci file failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Save aci file failed"}) return http.StatusInternalServerError, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func PutBlobsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { desc := ctx.Params(":uuid") uuid := strings.Split(desc, "?")[0] digest := ctx.Query("digest") tarsum := strings.Split(digest, ":")[1] imagePathTmp := module.GetImagePath(uuid, setting.APIVERSION_V2) layerPathTmp := module.GetLayerPath(uuid, "layer", setting.APIVERSION_V2) imagePath := module.GetImagePath(tarsum, setting.APIVERSION_V2) layerPath := module.GetLayerPath(tarsum, "layer", setting.APIVERSION_V2) reqbody, _ := ctx.Req.Body().Bytes() layerlen, err := module.SaveLayerLocal(imagePathTmp, layerPathTmp, imagePath, layerPath, reqbody) if err != nil { log.Error("[REGISTRY API V2] Failed to save layer %v: %v", layerPath, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to save layer file"}) return http.StatusInternalServerError, result } //saving specific tarsum every times is in order to split the same tarsum in HEAD handler i := new(models.Image) i.Path, i.Size = layerPath, int64(layerlen) if err := i.Save(tarsum); err != nil { log.Error("[REGISTRY API V2] Failed to save tarsum %v: %v", tarsum, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to save tarsum"}) return http.StatusBadRequest, result } random := fmt.Sprintf("%s://%s/v2/%s/%s/blobs/%s", setting.ListenMode, setting.Domains, ctx.Params(":namespace"), ctx.Params(":repository"), digest) 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.StatusCreated, result }
func PutBlobsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { desc := ctx.Params(":uuid") uuid := strings.Split(desc, "?")[0] digest := ctx.Query("digest") tarsum := strings.Split(digest, ":")[1] imagePathTmp := fmt.Sprintf("%v/%v", setting.ImagePath, uuid) layerfileTmp := fmt.Sprintf("%v/%v/layer", setting.ImagePath, uuid) imagePath := fmt.Sprintf("%v/tarsum/%v", setting.ImagePath, tarsum) layerfile := fmt.Sprintf("%v/tarsum/%v/layer", setting.ImagePath, tarsum) reqbody, _ := ctx.Req.Body().Bytes() layerlen, err := module.CopyImgLayer(imagePathTmp, layerfileTmp, imagePath, layerfile, reqbody) if err != nil { log.Error("[REGISTRY API V2] Save layerfile failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Save layerfile failed"}) return http.StatusBadRequest, result } //saving specific tarsum every times is in order to split the same tarsum in HEAD handler i := new(models.Image) i.Path, i.Size = layerfile, int64(layerlen) if err := i.PutTarsum(tarsum); err != nil { log.Error("[REGISTRY API V2] Save tarsum failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Save tarsum failed"}) return http.StatusBadRequest, result } random := fmt.Sprintf("%s://%s/v2/%s/%s/blobs/%s", setting.ListenMode, setting.Domains, ctx.Params(":namespace"), ctx.Params(":repository"), digest) ctx.Resp.Header().Set("Docker-Content-Digest", digest) ctx.Resp.Header().Set("Location", random) result, _ := json.Marshal(map[string]string{}) return http.StatusCreated, 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 }
func HeadBlobsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { digest := ctx.Params(":digest") tarsum := strings.Split(digest, ":")[1] i := new(models.Image) if has, _ := i.HasTarsum(tarsum); has == false { log.Info("[REGISTRY API V2] Tarsum not found: %v", tarsum) result, _ := json.Marshal(map[string]string{"message": "Tarsum not found"}) return http.StatusNotFound, result } ctx.Resp.Header().Set("Content-Type", "application/x-gzip") ctx.Resp.Header().Set("Docker-Content-Digest", digest) ctx.Resp.Header().Set("Content-Length", fmt.Sprint(i.Size)) result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func GetACIHandler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { var img []byte var err error name := ctx.Params(":acname") //support to fetch images from location storage, it will be supported to fetch from cloud etc. imgpath := setting.ImagePath + "/acpool/" + name if img, err = ioutil.ReadFile(imgpath); err != nil { // TBD: consider to fetch image from other storage medium log.Error("[ACI API] Get ACI file failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Get ACI file failed"}) return http.StatusNotFound, result } return http.StatusOK, img }
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 := fmt.Sprintf("%v/%v", setting.ImagePath, uuid) layerfileTmp := fmt.Sprintf("%v/%v/layer", setting.ImagePath, uuid) //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(layerfileTmp); err == nil { os.Remove(layerfileTmp) } data, _ := ioutil.ReadAll(ctx.Req.Request.Body) if err := ioutil.WriteFile(layerfileTmp, data, 0777); err != nil { log.Error("[REGISTRY API V2] Save layerfile failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Save layerfile failed"}) return http.StatusBadRequest, result } state := utils.MD5(fmt.Sprintf("%s/%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("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 }
func GetImageAncestryV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { imageId := ctx.Params(":imageId") i := new(models.Image) if has, _, err := i.Has(imageId); err != nil { log.Error("[REGISTRY API V1] Read Image Ancestry Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Read Image Ancestry Error"}) return http.StatusBadRequest, result } else if has == false { log.Error("[REGISTRY API V1] Read Image None: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Read Image None"}) return http.StatusNotFound, result } ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(i.Ancestry))) return http.StatusOK, []byte(i.Ancestry) }
func PutTagV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") tag := ctx.Params(":tag") bodystr, _ := ctx.Req.Body().String() rege, _ := regexp.Compile(`"([[:alnum:]]+)"`) imageIds := rege.FindStringSubmatch(bodystr) r := new(models.Repository) if err := r.PutTag(imageIds[1], namespace, repository, tag); err != nil { log.Error("[REGISTRY API V1] Failed to save repository %v/%v tag: %v", namespace, repository, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to save repository tag"}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
//Support to push acis func PostUploadHandler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") acifile := ctx.Params(":acifile") signfile := fmt.Sprintf("%v%v", acifile, ".asc") //TODO: only for testing,pubkey will be read and saved via user management module pubkeyspath := module.GetPubkeysPath(namespace, repository, setting.APIVERSION_ACI) if _, err := os.Stat(pubkeyspath); err != nil { if err := os.MkdirAll(pubkeyspath, os.ModePerm); err != nil { log.Error("[ACI API] Failed to create pubkeys path %v: %v", pubkeyspath, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to create pubkeys path"}) return http.StatusInternalServerError, result } } imageId := utils.MD5(uuid.NewV4().String()) imagepath := module.GetImagePath(imageId, setting.APIVERSION_ACI) if err := os.MkdirAll(imagepath, os.ModePerm); err != nil { log.Error("[ACI API] Failed to create aci path %v: %v", imagepath, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to create aci path"}) return http.StatusInternalServerError, result } prefix := fmt.Sprintf("%v://%v/ac/push/%v/%v/", setting.ListenMode, setting.Domains, namespace, repository) endpoint := models.UploadDetails{ ACIPushVersion: "0.0.1", //TODO: follow ACI push spec Multipart: false, ManifestURL: prefix + imageId + "/manifest", SignatureURL: prefix + imageId + "/signature/" + signfile, ACIURL: prefix + imageId + "/aci/" + acifile, CompletedURL: prefix + imageId + "/complete/" + acifile + "/" + signfile, } result, _ := json.Marshal(endpoint) return http.StatusOK, result }