352 lines
9.9 KiB
Go
352 lines
9.9 KiB
Go
/*
|
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
|
*/
|
|
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"mstore/app/imageoper"
|
|
"mstore/app/router"
|
|
"mstore/pkg/terms"
|
|
)
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary Get manifest info
|
|
// @Description Get manifest info
|
|
// @Tags manifest
|
|
// @Param name path string true "Manifest path"
|
|
// @Param reference path string true "Manifest tag"
|
|
// @Success 200
|
|
// @Failure 404,405,500
|
|
// @Router /v2/{name}/manifests/{reference} [HEAD]
|
|
// @Header 200 {string} Content-Length "Manifest size"
|
|
// @Header 200 {string} Content-Type "Manifest type"
|
|
// @Header 200 {string} Docker-Content-Digest "Manigest digest"
|
|
func (hand *Handler) ManifestExists(rctx *router.Context) {
|
|
name, _ := rctx.GetSubpath("name")
|
|
reference, _ := rctx.GetSubpath("reference")
|
|
|
|
hand.DumpHeaders("ManigestExists:\n", rctx)
|
|
|
|
params := &imageoper.ManifestExistsParams{
|
|
Name: name,
|
|
Reference: reference,
|
|
}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name)
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
ctx := rctx.GetContext()
|
|
res, code, err := hand.imop.ManifestExists(ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("ManifestExist error: %v", err)
|
|
} else if code == http.StatusOK {
|
|
rctx.SetHeader("Content-Length", res.ContentLength)
|
|
rctx.SetHeader("Content-Type", res.ContentType)
|
|
rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest)
|
|
}
|
|
hand.logg.Debugf(res.ContentType)
|
|
hand.logg.Debugf(res.DockerContentDigest)
|
|
rctx.SetStatus(code)
|
|
}
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary Put manifest
|
|
// @Description Put manifest
|
|
// @Tags manifest
|
|
// @Param name path string true "Manifest path"
|
|
// @Param reference path string true "Manifest tag"
|
|
// @Param Content-Length header string true "Manifest size"
|
|
// @Param Content-Type header string true "Manifest type"
|
|
// @Success 200
|
|
// @Failure 404,405,500
|
|
// @Router /v2/{name}/manifests/{reference} [PUT]
|
|
func (hand *Handler) PutManifest(rctx *router.Context) {
|
|
|
|
//hand.DumpHeaders("PutManifest headers", rctx)
|
|
|
|
contentType := rctx.GetHeader("Content-Type")
|
|
contentLength := rctx.GetHeader("Content-Length")
|
|
|
|
name, _ := rctx.GetSubpath("name")
|
|
reference, _ := rctx.GetSubpath("reference")
|
|
|
|
params := &imageoper.PutManifestParams{
|
|
ContentType: contentType,
|
|
ContentLength: contentLength,
|
|
Name: name,
|
|
Reference: reference,
|
|
Reader: rctx.Request.Body,
|
|
}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteImages, params.Name)
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
ctx := rctx.GetContext()
|
|
res, code, err := hand.imop.PutManifest(ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("PutManifest error: %v", err)
|
|
} else {
|
|
rctx.SetHeader("Location", res.Location)
|
|
}
|
|
rctx.SetStatus(code)
|
|
}
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary Get manifest
|
|
// @Description Get manifest
|
|
// @Tags manifest
|
|
// @Param name path string true "Manifest path"
|
|
// @Param reference path string true "Manifest tag"
|
|
// @Success 200
|
|
// @Failure 404,405,500
|
|
// @Router /v2/{name}/manifests/{reference} [GET]
|
|
// @Header 200 {string} Content-Length "Manifest size"
|
|
// @Header 200 {string} Content-Type "Manifest type"
|
|
// @Header 200 {string} Docker-Content-Digest "Manigest digest"
|
|
func (hand *Handler) GetManifest(rctx *router.Context) {
|
|
name, _ := rctx.GetSubpath("name")
|
|
reference, _ := rctx.GetSubpath("reference")
|
|
|
|
//hand.DumpHeaders("GetManigest", rctx)
|
|
|
|
params := &imageoper.GetManifestParams{
|
|
Name: name,
|
|
Reference: reference,
|
|
}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name)
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
ctx := rctx.GetContext()
|
|
res, code, err := hand.imop.GetManifest(ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("GetManifest error: %v", err)
|
|
rctx.SetStatus(code)
|
|
return
|
|
}
|
|
if code == http.StatusOK {
|
|
//hand.logg.Debugf("GetManifest type: %s", res.ContentType)
|
|
//hand.logg.Debugf("GetManifest payload: %s", res.Payload)
|
|
rctx.SetHeader("Content-Length", res.ContentLength)
|
|
rctx.SetHeader("Content-Type", res.ContentType)
|
|
rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest)
|
|
rctx.SendBytes(code, res.ContentType, []byte(res.Payload))
|
|
return
|
|
}
|
|
rctx.SetStatus(code)
|
|
}
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary Delete manifest
|
|
// @Description Delete manifest
|
|
// @Tags manifest
|
|
// @Param name path string true "Manifest path"
|
|
// @Param reference path string true "Manifest tag"
|
|
// @Success 202
|
|
// @Failure 404,405,500
|
|
// @Router /v2/{name}/manifests/{reference} [DELETE]
|
|
func (hand *Handler) DeleteManifest(rctx *router.Context) {
|
|
name, _ := rctx.GetSubpath("name")
|
|
reference, _ := rctx.GetSubpath("reference")
|
|
|
|
params := &imageoper.DeleteManifestParams{
|
|
Name: name,
|
|
Reference: reference,
|
|
}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteImages, params.Name)
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
ctx := rctx.GetContext()
|
|
_, code, err := hand.imop.DeleteManifest(ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("DeleteManifest error: %v", err)
|
|
}
|
|
rctx.SetStatus(code)
|
|
}
|
|
|
|
// GET /v2/<name>/referrers/<digest> 200 404/400
|
|
// GET /v2/<name>/referrers/<digest>?artifactType=<artifactType> 200 404/400
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary Get manifest referer
|
|
// @Description Get manifest referer
|
|
// @Tags manifest
|
|
// @Param name path string true "Manifest path"
|
|
// @Param digest path string true "Manifest digest"
|
|
// @Failure 404,405,500
|
|
// @Router /v2/{name}/referrers/{digest} [GET]
|
|
// @Success 200 {object} imageoper.GetRefererResult.Reference
|
|
// @Produce application/json
|
|
func (hand *Handler) GetReferer(rctx *router.Context) {
|
|
name, _ := rctx.GetSubpath("name")
|
|
digest, _ := rctx.GetSubpath("digest")
|
|
params := &imageoper.GetRefererParams{
|
|
Name: name,
|
|
Digest: digest,
|
|
}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name)
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
res, code, err := hand.imop.GetReferer(rctx.Ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("GetReferer error: %v", err)
|
|
}
|
|
rctx.SendText(code, res.Reference)
|
|
}
|
|
|
|
// GET /v2/<name>/tags/list 200 404
|
|
// GET /v2/<name>/tags/list?n=<integer>&last=<integer>
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary List manifest tags
|
|
// @Description List manifest tags
|
|
// @Tags manifest
|
|
// @Param name path string true "Manifest path"
|
|
// @Failure 404,405,500
|
|
// @Router /v2/{name}/tags/list [GET]
|
|
// @Success 200 {object} imageoper.GetTagsResult.TagDescr
|
|
// @Produce application/json
|
|
func (hand *Handler) GetTags(rctx *router.Context) {
|
|
name, _ := rctx.GetSubpath("name")
|
|
params := &imageoper.GetTagsParams{
|
|
Name: name,
|
|
}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, params.Name)
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
ctx := rctx.GetContext()
|
|
res, code, err := hand.imop.GetTags(ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("GetTags error: %v", err)
|
|
}
|
|
rctx.SendJSON(code, res.TagDescr)
|
|
}
|
|
|
|
// GET /v2/_catalog?n=1000 200 404
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary List manifests
|
|
// @Description List manifests
|
|
// @Tags manifest
|
|
// @Failure 404,405,500
|
|
// @Router /v2/_catalog [GET]
|
|
// @Success 200 {object} imageoper.ListManifestsResult.Repositories
|
|
// @Produce application/json
|
|
func (hand *Handler) ListManifests(rctx *router.Context) {
|
|
params := &imageoper.ListManifestsParams{}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadImages, "_catalog")
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
ctx := rctx.GetContext()
|
|
res, code, err := hand.imop.ListManifests(ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("ListManifests error: %v", err)
|
|
}
|
|
|
|
rctx.SendJSON(code, res.Repositories)
|
|
}
|
|
|
|
// GetProperty godoc
|
|
//
|
|
// @Summary Check images
|
|
// @Description Check images
|
|
// @Tags manifest
|
|
// @Failure 404,405,500
|
|
// @Router /v2/checker/{name} [POST]
|
|
// @Router /v2/checker/ [POST]
|
|
// @Success 200 {object} imageoper.CheckImagesResult.Repositories
|
|
// @Produce application/json
|
|
func (hand *Handler) CheckImages(rctx *router.Context) {
|
|
name, _ := rctx.GetSubpath("name")
|
|
params := &imageoper.CheckImagesParams{
|
|
Name: name,
|
|
}
|
|
// Rigth checking
|
|
operatorID, _ := rctx.GetString(userTag)
|
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteImages, name)
|
|
if err != nil {
|
|
rctx.SetStatus(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if !opEnable {
|
|
rctx.SetStatus(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
// Execution of the operation
|
|
ctx := rctx.GetContext()
|
|
res, code, err := hand.imop.CheckImages(ctx, params)
|
|
if err != nil {
|
|
hand.logg.Errorf("CheckImages error: %v", err)
|
|
}
|
|
rctx.SendJSON(code, res.Repositories)
|
|
}
|