feat: as docker mirror registry

feat: add global proxy config
upgrade: upgrade front(angular) to 19
chore: deployment staff
  1. Dockerfile: build frontend, backend, and run in nginx base image
This commit is contained in:
loveuer
2024-12-23 00:07:44 -08:00
parent aac6c67a5f
commit 6e866b83e4
57 changed files with 22226 additions and 7343 deletions

View File

@ -3,17 +3,18 @@ package handler
import (
"errors"
"fmt"
"github.com/loveuer/nf"
"github.com/sirupsen/logrus"
"io"
"log"
"net/http"
"nf-repo/internal/model"
"nf-repo/internal/opt"
"nf-repo/internal/util/rerr"
"nf-repo/internal/verify"
"path"
"strings"
"nf-repo/internal/model"
"nf-repo/internal/opt"
"nf-repo/internal/tool/rerr"
"nf-repo/internal/verify"
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/log"
)
func handleBlobs(c *nf.Ctx) error {
@ -39,15 +40,8 @@ func handleBlobs(c *nf.Ctx) error {
rangeHeader := c.Get("Range")
repo := c.Request.URL.Host + path.Join(elem[1:len(elem)-2]...)
logrus.
WithField("handler", "handleBlob").
WithField("path", c.Path()).
WithField("method", c.Method()).
WithField("target", target).
WithField("service", service).
WithField("repo", repo).
WithField("digest", digest).
Debug()
log.Debug("handleBlob: path = %s, method = %s, target = %s, service = %s, repo = %s, digest = %s",
c.Path(), c.Method(), target, service, repo, digest)
switch c.Method() {
case http.MethodHead:
@ -68,7 +62,7 @@ func handleBlobs(c *nf.Ctx) error {
} else if err != nil {
var re model.RedirectError
if errors.As(err, &re) {
http.Redirect(c.RawWriter(), c.Request, re.Location, re.Code)
http.Redirect(c.Writer, c.Request, re.Location, re.Code)
return nil
}
return rerr.Error(c, rerr.ErrInternal(err))
@ -93,11 +87,12 @@ func handleBlobs(c *nf.Ctx) error {
size, err = b.blobHandler.Stat(c.Request.Context(), repo, h)
if errors.Is(err, opt.ErrNotFound) {
log.Error("handleBlobs: mirror registry get repo not found, repo = %s", repo)
return rerr.Error(c, rerr.ErrBlobUnknown)
} else if err != nil {
var re model.RedirectError
if errors.As(err, &re) {
http.Redirect(c.RawWriter(), c.Request, re.Location, re.Code)
http.Redirect(c.Writer, c.Request, re.Location, re.Code)
return nil
}
@ -110,7 +105,7 @@ func handleBlobs(c *nf.Ctx) error {
} else if err != nil {
var re model.RedirectError
if errors.As(err, &re) {
http.Redirect(c.RawWriter(), c.Request, re.Location, re.Code)
http.Redirect(c.Writer, c.Request, re.Location, re.Code)
return nil
}
@ -162,7 +157,7 @@ func handleBlobs(c *nf.Ctx) error {
c.Status(http.StatusOK)
}
_, err = io.Copy(c.RawWriter(), r)
_, err = io.Copy(c.Writer, r)
return err
case http.MethodPost:
@ -190,7 +185,7 @@ func handleBlobs(c *nf.Ctx) error {
if err = b.blobHandler.Put(c.Request.Context(), repo, h, vrc); err != nil {
if errors.As(err, &verify.Error{}) {
log.Printf("Digest mismatch: %v", err)
log.Info("Digest mismatch: %v", err)
return rerr.Error(c, rerr.ErrDigestMismatch)
}
return rerr.Error(c, rerr.ErrInternal(err))

View File

@ -1,12 +1,14 @@
package handler
import (
"github.com/loveuer/nf"
"net/http"
"strconv"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/util/rerr"
"strconv"
"nf-repo/internal/tool/rerr"
"github.com/loveuer/nf"
)
func handleCatalog(ctx *nf.Ctx, m interfaces.ManifestHandler) error {

View File

@ -2,30 +2,30 @@ package handler
import (
"bytes"
"encoding/json"
"fmt"
"github.com/loveuer/nf"
"github.com/sirupsen/logrus"
"io"
"net/http"
"strings"
"nf-repo/internal/controller"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/util/rerr"
"strings"
"nf-repo/internal/tool/rerr"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/log"
)
func handleManifest(ctx *nf.Ctx, m interfaces.ManifestHandler) error {
func handleManifest(ctx *nf.Ctx, m interfaces.ManifestHandler, blobHandler interfaces.BlobHandler) error {
elem := strings.Split(ctx.Path(), "/")
elem = elem[1:]
target := elem[len(elem)-1]
repo := strings.Join(elem[1:len(elem)-2], "/")
logrus.
WithField("handler", "handleManifest").
WithField("path", ctx.Path()).
WithField("method", ctx.Method()).
WithField("repo", repo).
WithField("target", target).
Debug()
log.Debug("handleManifest: path = %s, method = %s, repo = %s, target = %s",
ctx.Path(), ctx.Method(), repo, target)
switch ctx.Method() {
case http.MethodGet:
@ -38,6 +38,22 @@ func handleManifest(ctx *nf.Ctx, m interfaces.ManifestHandler) error {
)
if reader, contentType, re = m.Get(ctx.Request.Context(), repo, target); re != nil {
if re.Status == 404 {
log.Debug("handleManifest: repo not found, start pull, repo = %s, tag = %s", repo, target)
var manifest *v1.Manifest
if manifest, err = controller.PullRepo(ctx.Context(), repo, target, "", m, blobHandler); err != nil {
return rerr.Error(ctx, &rerr.RepositoryError{
Status: http.StatusInternalServerError,
Code: "INTERNAL_SERVER_ERROR",
Message: err.Error(),
})
}
contentType = string(manifest.MediaType)
bs, _ = json.Marshal(manifest)
goto RETURN_GET
}
return rerr.Error(ctx, re)
}
@ -49,6 +65,8 @@ func handleManifest(ctx *nf.Ctx, m interfaces.ManifestHandler) error {
})
}
RETURN_GET:
h, _, _ := model.SHA256(bytes.NewReader(bs))
ctx.Set("Docker-Content-Digest", h.String())
ctx.Set("Content-Type", contentType)
@ -107,16 +125,8 @@ func handleManifest(ctx *nf.Ctx, m interfaces.ManifestHandler) error {
ContentType: ctx.Get("Content-Type"),
}
logrus.
WithField("handler", "handleManifest").
WithField("path", ctx.Path()).
WithField("method", ctx.Method()).
WithField("repo", repo).
WithField("target", target).
WithField("digest", digest).
WithField("content-type", ctx.Get("Content-Type")).
WithField("content", buf.String()).
Debug()
log.Debug("handleManifest: path = %s, method = %s, repo = %s, target = %s, digest = %s, content-type = %s, content = %s",
ctx.Path(), ctx.Method(), repo, target, digest, ctx.Get("Content-Type"), buf.String())
if err := m.Put(ctx.Request.Context(), repo, target, digest, &mf); err != nil {
return rerr.Error(ctx, err)

View File

@ -4,14 +4,16 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/loveuer/nf"
"io"
"net/http"
"strings"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/model/types"
"nf-repo/internal/util/rerr"
"strings"
"nf-repo/internal/tool/rerr"
"github.com/loveuer/nf"
)
func handleReferrers(ctx *nf.Ctx, m interfaces.ManifestHandler) error {
@ -51,7 +53,7 @@ func handleReferrers(ctx *nf.Ctx, m interfaces.ManifestHandler) error {
ctx.Set("Content-Length", fmt.Sprint(len(msg)))
ctx.Set("Content-Type", string(types.OCIImageIndex))
ctx.Status(http.StatusOK)
_, err = io.Copy(ctx.RawWriter(), bytes.NewReader(msg))
_, err = io.Copy(ctx.Writer, bytes.NewReader(msg))
return err
}

View File

@ -4,25 +4,28 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/loveuer/nf"
"github.com/sirupsen/logrus"
"io"
"net/http"
"net/url"
"strings"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/opt"
"nf-repo/internal/util/r"
"nf-repo/internal/util/rerr"
"strings"
"nf-repo/internal/tool/r"
"nf-repo/internal/tool/rerr"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/log"
"github.com/loveuer/nf/nft/resp"
)
func RepoSettings(c *nf.Ctx) error {
return r.Resp200(c, nf.Map{
"base_address": opt.BaseAddress,
return resp.Resp200(c, nf.Map{
"repo_name": opt.Cfg.RepoName,
})
}
@ -42,7 +45,7 @@ func RepoList(mh interfaces.ManifestHandler) nf.HandlerFunc {
)
if err = c.QueryParser(req); err != nil {
return r.Resp400(c, err.Error())
return resp.Resp400(c, err.Error())
}
if req.N == 0 {
@ -50,14 +53,14 @@ func RepoList(mh interfaces.ManifestHandler) nf.HandlerFunc {
}
if req.N > 1000 {
return r.Resp400(c, "limit invalid: too big")
return resp.Resp400(c, "limit invalid: too big")
}
if catalog, re = mh.Catalog(c.Request.Context(), req.N, req.Last, req.Keyword); re != nil {
return r.Resp(c, uint32(re.Status), "", re.Code, re.Message)
return resp.Resp(c, uint32(re.Status), "", re.Code, re.Message)
}
return r.Resp200(c, nf.Map{"list": catalog.Repos, "total": 0})
return resp.Resp200(c, nf.Map{"list": catalog.Repos, "total": 0})
}
}
@ -127,7 +130,7 @@ func ProxyDownloadImage(mh interfaces.ManifestHandler, bh interfaces.BlobHandler
manifest *v1.Manifest
bs []byte
mhash model.Hash
//progressCh = make(chan v1.Update, 16)
// progressCh = make(chan v1.Update, 16)
)
if err = c.BodyParser(req); err != nil {
@ -144,21 +147,18 @@ func ProxyDownloadImage(mh interfaces.ManifestHandler, bh interfaces.BlobHandler
}
repo, tag := repoTags[0], repoTags[1]
repo = strings.TrimPrefix(repo, opt.BaseAddress)
repo = strings.TrimPrefix(repo, opt.Cfg.RepoName)
repo = strings.Trim(repo, "/")
if req.Source == "" {
return r.Resp400(c, "source invalid")
}
imageName := fmt.Sprintf("%s/%s:%s", opt.BaseAddress, repo, tag)
_ = imageName
log.Debug("ProxyDownloadImage: req = %#v, repo = %s", *req, repo)
logrus.
WithField("path", "handler.ProxyDownloadImage").
WithField("req", *req).
WithField("repo", repo).
Debug()
if opt.Proxy != nil {
transport.Proxy = http.ProxyURL(opt.Proxy)
}
if req.Proxy != "" {
var pu *url.URL

View File

@ -1,11 +1,12 @@
package handler
import (
"github.com/loveuer/nf"
"github.com/sirupsen/logrus"
"nf-repo/internal/interfaces"
"nf-repo/internal/opt"
"nf-repo/internal/util/rerr"
"nf-repo/internal/tool/rerr"
"github.com/loveuer/nf"
"github.com/loveuer/nf/nft/log"
)
type blob struct {
@ -13,9 +14,7 @@ type blob struct {
uploadHandler interfaces.UploadHandler
}
var (
b = &blob{}
)
var b = &blob{}
func Root(bh interfaces.BlobHandler, uh interfaces.UploadHandler, mh interfaces.ManifestHandler) nf.HandlerFunc {
b.blobHandler = bh
@ -26,7 +25,7 @@ func Root(bh interfaces.BlobHandler, uh interfaces.UploadHandler, mh interfaces.
}
if isManifest(c) {
return handleManifest(c, mh)
return handleManifest(c, mh, bh)
}
if isTags(c) {
@ -43,11 +42,7 @@ func Root(bh interfaces.BlobHandler, uh interfaces.UploadHandler, mh interfaces.
c.SetHeader("Docker-Distribution-API-Version", "registry/2.0")
logrus.
WithField("path", c.Path()).
WithField("method", c.Method()).
WithField("headers", c.Request.Header).
Warn()
log.Warn("root.go Root: path = %s, method = %s, headers = %v", c.Path(), c.Method(), c.Request.Header)
return rerr.Error(c, rerr.ErrUnauthorized)
}

View File

@ -1,12 +1,14 @@
package handler
import (
"github.com/loveuer/nf"
"net/http"
"strings"
"nf-repo/internal/interfaces"
"nf-repo/internal/model"
"nf-repo/internal/util/rerr"
"strings"
"nf-repo/internal/tool/rerr"
"github.com/loveuer/nf"
)
func handleTags(ctx *nf.Ctx, m interfaces.ManifestHandler) error {