예제 #1
0
//HeadBlobsV2Handler is
func HeadBlobsV2Handler(ctx *macaron.Context) (int, []byte) {
	digest := ctx.Params(":digest")
	tarsum := strings.Split(digest, ":")[1]

	i := new(models.DockerImageV2)
	if err := i.Get(tarsum); err != nil && err == gorm.ErrRecordNotFound {
		log.Info("Not found blob: %s", tarsum)

		result, _ := module.EncodingError(module.BLOB_UNKNOWN, digest)
		return http.StatusNotFound, result
	} else if err != nil && err != gorm.ErrRecordNotFound {
		log.Info("Failed to get blob %s: %s", tarsum, err.Error())

		result, _ := module.EncodingError(module.UNKNOWN, err.Error())
		return http.StatusBadRequest, result
	}

	ctx.Resp.Header().Set("Content-Type", "application/json; charset=utf-8")
	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
}
예제 #2
0
//GetBlobsV2Handler is
func GetBlobsV2Handler(ctx *macaron.Context) {
	digest := ctx.Params(":digest")
	tarsum := strings.Split(digest, ":")[1]

	i := new(models.DockerImageV2)
	if err := i.Get(tarsum); err != nil && err == gorm.ErrRecordNotFound {
		log.Info("Not found blob: %s", tarsum)

		result, _ := module.EncodingError(module.BLOB_UNKNOWN, digest)
		ctx.Resp.Write(result)
		ctx.Resp.WriteHeader(http.StatusBadRequest)
		return
	} else if err != nil && err != gorm.ErrRecordNotFound {
		log.Info("Failed to get blob %s: %s", tarsum, err.Error())

		result, _ := module.EncodingError(module.UNKNOWN, err.Error())
		ctx.Resp.Write(result)
		ctx.Resp.WriteHeader(http.StatusBadRequest)
		return
	}

	if file, err := os.Open(i.Path); err != nil {
		log.Info("Failed to get blob %s: %s", tarsum, err.Error())

		result, _ := module.EncodingError(module.UNKNOWN, err.Error())
		ctx.Resp.Write(result)
		ctx.Resp.WriteHeader(http.StatusBadRequest)
		return
	} else {
		stat, _ := file.Stat()
		size := strconv.FormatInt(stat.Size(), 10)

		ctx.Resp.Header().Set("Content-Description", "File Transfer")
		ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
		ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", i.ImageID))
		ctx.Resp.Header().Set("Content-Length", size)
		ctx.Resp.Header().Set("Docker-Content-Digest", digest)
		ctx.Resp.Header().Set("Expires", "0")
		ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
		ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
		ctx.Resp.Header().Set("Pragma", "public")

		file.Seek(0, 0)
		defer file.Close()

		io.Copy(ctx.Resp, file)
		ctx.Resp.WriteHeader(http.StatusOK)
		return
	}
}
예제 #3
0
//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
}