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 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 GetBlobsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { digest := ctx.Params(":digest") tarsum := strings.Split(digest, ":")[1] i := new(models.Image) if exists, err := i.Get(tarsum); err != nil { log.Error("[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.Error("[REGISTRY API V2] Not found tarsum: %v: %v", tarsum, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Not found tarsum"}) return http.StatusNotFound, result } layer, err := module.DownloadLayer(i.Path) if err != nil { log.Error("[REGISTRY API V2] Failed to get layer: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to read layer file"}) return http.StatusInternalServerError, 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(len(layer))) return http.StatusOK, layer }
func GetImageLayerV1Handler(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 layer: %v", imageId, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to get image layer"}) return http.StatusNotFound, result } layerfile := i.Path if _, err := os.Stat(layerfile); err != nil { log.Error("[REGISTRY API V1] Image layer file state error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Image layer file state error"}) return http.StatusInternalServerError, result } file, err := ioutil.ReadFile(layerfile) if err != nil { log.Error("[REGISTRY API V1] Failed to read image layer: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to read image layer"}) return http.StatusInternalServerError, result } ctx.Resp.Header().Set("Content-Type", "application/octet-stream") ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(file))) return http.StatusOK, file }
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 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 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 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 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 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 GetACIHandler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") acifilename := ctx.Params(":acifilename") acifile := strings.Trim(acifilename, ".asc") tag := strings.Trim(acifile, ".aci") t := new(models.Tag) if exists, err := t.Get(namespace, repository, tag); err != nil || !exists { log.Error("[ACI API] Not found ACI %v/%v/%v", namespace, repository, acifilename) result, _ := json.Marshal(map[string]string{"message": "Not found ACI"}) return http.StatusNotFound, result } i := new(models.Image) if exists, err := i.Get(t.ImageId); err != nil || !exists { log.Error("[ACI API] Not found ACI %v/%v/%v", namespace, repository, acifilename) result, _ := json.Marshal(map[string]string{"message": "Not found ACI"}) return http.StatusNotFound, result } var filepath string if b := strings.Contains(acifilename, ".asc"); b == true { filepath = i.SignPath } else { filepath = i.AciPath } content, err := ioutil.ReadFile(filepath) if err != nil { log.Error("[ACI API] Failed to get ACI file %v: %v", filepath, err.Error()) result, _ := json.Marshal(map[string]string{"message": "Failed to get ACI file"}) return http.StatusInternalServerError, result } return http.StatusOK, content }
func PutImageJSONV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { imageId := ctx.Params(":imageId") info, 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 image JSON failed,request body is empty"}) return http.StatusBadRequest, result } i := new(models.Image) if err := i.PutJSON(imageId, info, setting.APIVERSION_V1); err != nil { log.Error("[REGISTRY API V1] Put Image JSON Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Put Image JSON Error"}) return http.StatusBadRequest, result } result, _ := json.Marshal(map[string]string{}) return http.StatusOK, result }
func GetImageLayerV1Handler(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 Layer File Status Error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Read Image Layer file Error"}) return http.StatusBadRequest, result } else if has == false { log.Error("[REGISTRY API V1] Read Image None Error") result, _ := json.Marshal(map[string]string{"message": "Read Image None"}) return http.StatusNotFound, result } layerfile := i.Path if _, err := os.Stat(layerfile); err != nil { log.Error("[REGISTRY API V1] Read Image file state error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Read Image file state error"}) return http.StatusBadRequest, result } file, err := ioutil.ReadFile(layerfile) if err != nil { log.Error("[REGISTRY API V1] Read Image file error: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Read Image file error"}) return http.StatusBadRequest, result } ctx.Resp.Header().Set("Content-Type", "application/octet-stream") ctx.Resp.Header().Set("Content-Length", fmt.Sprint(len(file))) return http.StatusOK, file }
func GetBlobsV2Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) { digest := ctx.Params(":digest") tarsum := strings.Split(digest, ":")[1] i := new(models.Image) has, _ := i.HasTarsum(tarsum) if has == false { log.Error("[REGISTRY API V2] Digest not found: %v", tarsum) result, _ := json.Marshal(map[string]string{"message": "Digest not found"}) return http.StatusNotFound, result } layerfile := i.Path if _, err := os.Stat(layerfile); err != nil { log.Error("[REGISTRY API V2] File path is invalid: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "File path is invalid"}) return http.StatusBadRequest, result } file, err := ioutil.ReadFile(layerfile) if err != nil { log.Error("[REGISTRY API V2] Read file failed: %v", err.Error()) result, _ := json.Marshal(map[string]string{"message": "Read file failed"}) return http.StatusBadRequest, 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(len(file))) return http.StatusOK, file }
//Upload the layer of image to object storage service,support to analyzed docker V1/V2 manifest now //consider recycling resources while save to oss failure,get and delete should be support soon func UploadLayer(tarsumlist []string) error { if backend.Drv == nil { return nil } if len(tarsumlist) <= 0 { return fmt.Errorf("no blobs") } for _, tarsum := range tarsumlist { i := new(models.Image) if exists, err := i.Get(tarsum); err != nil { return err } else if !exists { return fmt.Errorf("not found tarsum") } if _, err := backend.Drv.Save(i.Path); err != nil { return err } } return nil }
func (n *notification) Handler(ctx *macaron.Context) { namespace := ctx.Params(":namespace") repository := ctx.Params(":repository") //Notification function just supports DockerV2 now r := new(models.Repository) if exists, err := r.Get(namespace, repository); err != nil || exists == false { return } if r.Version != setting.APIVERSION_V2 { return } actor := ActorRecord{Name: namespace} repo := fmt.Sprintf("%v/%v", namespace, repository) switch ctx.Req.Method { case "HEAD": digest := ctx.Params(":digest") tarsum := strings.Split(digest, ":")[1] i := new(models.Image) if exists, _ := i.Get(tarsum); exists == false { return } desc := Descriptor{ MediaType: DefaultMedisType, Size: i.Size, Digest: digest, } req := newReqRecord(utils.EncodeBasicAuth(namespace, "headblobsv2"), ctx.Req.Request) requrl, err := module.NewURLBuilderFromRequest(ctx.Req.Request).BuildBlobURL(repo, desc.Digest) if err != nil { fmt.Errorf("[REGISTRY API V2] Head blobs and get request URL failed, error:: %v", err.Error()) } b := newBridge(requrl, actor, req, notice) Err := b.createBlobEventAndWrite(EventActionPull, repo, desc) if Err.Err != nil { ctx.Resp.WriteHeader(http.StatusForbidden) return } else if Err.StatusCode >= 300 { ctx.Resp.WriteHeader(Err.StatusCode) return } case "GET": if flag := utils.Compare(ctx.Req.RequestURI, "/v2/"); flag == 0 { return } if flag := strings.Contains(ctx.Req.RequestURI, "/blobs/"); flag == true { digest := ctx.Params(":digest") tarsum := strings.Split(digest, ":")[1] i := new(models.Image) if exists, _ := i.Get(tarsum); exists == false { return } desc := Descriptor{ MediaType: BlobMediaType, Size: i.Size, Digest: digest, } req := newReqRecord(utils.EncodeBasicAuth(namespace, "getblobsv2"), ctx.Req.Request) requrl, err := module.NewURLBuilderFromRequest(ctx.Req.Request).BuildBlobURL(repo, desc.Digest) if err != nil { fmt.Errorf("[REGISTRY API V2] Get blobs and get request URL failed, error:: %v", err.Error()) } b := newBridge(requrl, actor, req, notice) Err := b.createBlobEventAndWrite(EventActionPull, repo, desc) if Err.Err != nil { ctx.Resp.WriteHeader(http.StatusForbidden) return } else if Err.StatusCode >= 300 { ctx.Resp.WriteHeader(Err.StatusCode) return } return } if flag := strings.Contains(ctx.Req.RequestURI, "/manifests/"); flag == true { t := new(models.Tag) if exists, err := t.Get(namespace, repository, ctx.Params(":tag")); err != nil || !exists { return } digest, err := utils.DigestManifest([]byte(t.Manifest)) if err != nil { fmt.Errorf("[REGISTRY API V2] Get manifest digest failed: %v", err.Error()) return } var sm SignedManifest if err := json.Unmarshal([]byte(t.Manifest), &sm); err != nil { fmt.Errorf("Unmarshal manifest error") } sm.Raw = make([]byte, len(t.Manifest), len(t.Manifest)) copy(sm.Raw, []byte(t.Manifest)) req := newReqRecord(utils.EncodeBasicAuth(namespace, "getmanifestv2"), ctx.Req.Request) requrl, err := module.NewURLBuilderFromRequest(ctx.Req.Request).BuildManifestURL(sm.Name, digest) if err != nil { fmt.Errorf("[REGISTRY API V2] Get manifest and get request URL failed, error:: %v", err.Error()) } b := newBridge(requrl, actor, req, notice) Err := b.createManifestEventAndWrite(EventActionPull, repo, &sm) if Err.Err != nil { ctx.Resp.WriteHeader(http.StatusForbidden) return } else if Err.StatusCode >= 300 { ctx.Resp.WriteHeader(Err.StatusCode) return } return } case "PUT": if flag := strings.Contains(ctx.Req.RequestURI, "/blobs/uploads/"); flag == true { param := ctx.Params(":uuid") uuid := strings.Split(param, "?")[0] layer, _ := ioutil.ReadFile(fmt.Sprintf("%v/%v/layer", setting.ImagePath, uuid)) digest := ctx.Query("digest") desc := Descriptor{ MediaType: DefaultMedisType, Size: int64(len(layer)), Digest: digest, } req := newReqRecord(utils.EncodeBasicAuth(namespace, "putblobsv2"), ctx.Req.Request) requrl, err := module.NewURLBuilderFromRequest(ctx.Req.Request).BuildBlobURL(repo, desc.Digest) if err != nil { fmt.Errorf("[REGISTRY API V2] Get blobs and get request URL failed, error:: %v", err.Error()) } b := newBridge(requrl, actor, req, notice) Err := b.createBlobEventAndWrite(EventActionPush, repo, desc) if Err.Err != nil { ctx.Resp.WriteHeader(http.StatusForbidden) return } else if Err.StatusCode >= 300 { ctx.Resp.WriteHeader(Err.StatusCode) return } return } if flag := strings.Contains(ctx.Req.RequestURI, "/manifests/"); flag == true { buf, _ := ctx.Req.Body().Bytes() handler.ManifestCtx = buf var sm SignedManifest if err := json.Unmarshal(buf, &sm); err != nil { fmt.Errorf("Unmarshal manifest error") } sm.Raw = make([]byte, len(buf), len(buf)) copy(sm.Raw, buf) digest, err := utils.DigestManifest(buf) if err != nil { fmt.Errorf("[REGISTRY API V2] Get manifest digest failed: %v", err.Error()) //return http.StatusBadRequest, result } req := newReqRecord(utils.EncodeBasicAuth(namespace, "putmanifestv2"), ctx.Req.Request) requrl, err := module.NewURLBuilderFromRequest(ctx.Req.Request).BuildManifestURL(sm.Name, digest) if err != nil { fmt.Errorf("[REGISTRY API V2] Put manifest and get request URL failed, error:: %v", err.Error()) } b := newBridge(requrl, actor, req, notice) Err := b.createManifestEventAndWrite(EventActionPush, repo, &sm) if Err.Err != nil { ctx.Resp.WriteHeader(http.StatusForbidden) return } else if Err.StatusCode >= 300 { ctx.Resp.WriteHeader(Err.StatusCode) return } return } default: return } }