Example #1
0
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)
}
Example #2
0
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
}
Example #3
0
func GetTagV1Handler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) {
	namespace := ctx.Params(":namespace")
	repository := ctx.Params(":repository")

	r := new(models.Repository)
	if exists, err := r.Get(namespace, repository); err != nil {
		log.Error("[REGISTRY API V1] Failed to get repository %v/%v context: %v", namespace, repository, err.Error())

		result, _ := json.Marshal(map[string]string{"message": "Failed to get repository context"})
		return http.StatusBadRequest, result
	} else if exists == false {
		log.Error("[REGISTRY API V1] Not found repository %v/%v", namespace, repository)

		result, _ := json.Marshal(map[string]string{"message": "Not found repository"})
		return http.StatusNotFound, result
	}

	tags := map[string]string{}
	tagslist := r.GetTagslist()
	for _, tagname := range tagslist {
		t := new(models.Tag)
		if exists, err := t.Get(namespace, repository, tagname); err != nil || !exists {
			log.Error(fmt.Sprintf("[REGISTRY API V1]  %s/%s %v is not exist", namespace, repository, tagname))

			result, _ := json.Marshal(map[string]string{"message": "Tag is not exist"})
			return http.StatusNotFound, result
		}

		tags[tagname] = t.ImageId
	}

	result, _ := json.Marshal(tags)
	return http.StatusOK, result
}
Example #4
0
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)
}
Example #5
0
func PostCompleteHandler(ctx *macaron.Context, log *logs.BeeLogger) (int, []byte) {
	imageId := ctx.Params(":imageId")
	repository := ctx.Params(":repository")

	body, _ := ctx.Req.Body().Bytes()
	if err := module.CheckClientStatus(body); err != nil {
		module.CleanCache(imageId, setting.APIVERSION_ACI)
		log.Error("[ACI API] Failed to push aci: %v", err.Error())

		failmsg := module.FillRespMsg(false, err.Error(), "")
		result, _ := json.Marshal(failmsg)
		return http.StatusInternalServerError, result
	}

	namespace := ctx.Params(":namespace")
	acifile := ctx.Params(":acifile")
	signfile := ctx.Params(":signfile")

	//TODO: only for testing,pubkey will be read and saved via user management module
	pubkeyspath := module.GetPubkeysPath(namespace, repository, setting.APIVERSION_ACI)
	acifilepath := module.GetLayerPath(imageId, acifile, setting.APIVERSION_ACI)
	signfilepath := module.GetSignaturePath(imageId, signfile, setting.APIVERSION_ACI)
	manipath := module.GetManifestPath(imageId, setting.APIVERSION_ACI)
	if err := module.VerifyAciSignature(acifilepath, signfilepath, pubkeyspath); err != nil {
		module.CleanCache(imageId, setting.APIVERSION_ACI)
		log.Error("[ACI API] Failed to verify Aci: %v", err.Error())

		failmsg := module.FillRespMsg(false, "", err.Error())
		result, _ := json.Marshal(failmsg)
		return http.StatusInternalServerError, result
	}

	//If aci image is existent,it should update the db and delete the old image after executed successfully
	var oldimageId = ""
	tag := strings.Trim(acifile, ".aci")
	t := new(models.Tag)
	if exists, err := t.Get(namespace, repository, tag); err == nil && exists {
		oldimageId = t.ImageId
	}

	a := new(models.Aci)
	if err := a.Update(namespace, repository, tag, imageId, manipath, signfilepath, acifilepath); err != nil {
		module.CleanCache(imageId, setting.APIVERSION_ACI)
		log.Error("[ACI API] Failed to update %v/%v: %v", namespace, repository, err.Error())

		failmsg := module.FillRespMsg(false, "", err.Error())
		result, _ := json.Marshal(failmsg)
		return http.StatusInternalServerError, result
	}

	//Delete old aci directory after redis is updated
	if oldimageId != "" {
		module.CleanCache(oldimageId, setting.APIVERSION_ACI)
	}

	successmsg := module.FillRespMsg(true, "", "")
	result, _ := json.Marshal(successmsg)
	return http.StatusOK, result
}
Example #6
0
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
}
Example #7
0
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
	}
}