Files
mstore/app/handler/manifest.go
T
2026-05-13 17:21:22 +02:00

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)
}