working commit
This commit is contained in:
+3
-3
@@ -41,8 +41,8 @@ EXTRA_mstorectl_SOURCES = \
|
|||||||
cmd/mstorectl/imagecmd/imagetags.go \
|
cmd/mstorectl/imagecmd/imagetags.go \
|
||||||
cmd/mstorectl/imagecmd/printresp.go \
|
cmd/mstorectl/imagecmd/printresp.go \
|
||||||
cmd/mstorectl/imagecmd/gcrimageconf.go \
|
cmd/mstorectl/imagecmd/gcrimageconf.go \
|
||||||
cmd/mstorectl/imagecmd/gcrpullimage.go \
|
cmd/mstorectl/imagecmd/pullimage.go \
|
||||||
cmd/mstorectl/imagecmd/gcrpushimage.go
|
cmd/mstorectl/imagecmd/pushimage.go
|
||||||
|
|
||||||
mstored_SOURCES = cmd/mstored/main.go
|
mstored_SOURCES = cmd/mstored/main.go
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ mstored$(EXEEXT): $(mstored_SOURCES) $(EXTRA_mstored_SOURCES)
|
|||||||
env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mstored$(EXEEXT) $(mstored_SOURCES)
|
env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mstored$(EXEEXT) $(mstored_SOURCES)
|
||||||
|
|
||||||
run: $(mstored_SOURCES)
|
run: $(mstored_SOURCES)
|
||||||
cd cmd/mstored && env CGO_ENABLED=1 $(GO) run . --asDaemon=false
|
cd cmd/mstored && env CGO_ENABLED=1 $(GO) run . --asDaemon=false --port=443
|
||||||
|
|
||||||
CWD=$(shell pwd)
|
CWD=$(shell pwd)
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -387,8 +387,8 @@ EXTRA_mstorectl_SOURCES = \
|
|||||||
cmd/mstorectl/imagecmd/imagetags.go \
|
cmd/mstorectl/imagecmd/imagetags.go \
|
||||||
cmd/mstorectl/imagecmd/printresp.go \
|
cmd/mstorectl/imagecmd/printresp.go \
|
||||||
cmd/mstorectl/imagecmd/gcrimageconf.go \
|
cmd/mstorectl/imagecmd/gcrimageconf.go \
|
||||||
cmd/mstorectl/imagecmd/gcrpullimage.go \
|
cmd/mstorectl/imagecmd/pullimage.go \
|
||||||
cmd/mstorectl/imagecmd/gcrpushimage.go
|
cmd/mstorectl/imagecmd/pushimage.go
|
||||||
|
|
||||||
mstored_SOURCES = cmd/mstored/main.go
|
mstored_SOURCES = cmd/mstored/main.go
|
||||||
EXTRA_mstored_SOURCES = cmd/mstored/starter/starter.go \
|
EXTRA_mstored_SOURCES = cmd/mstored/starter/starter.go \
|
||||||
@@ -1130,7 +1130,7 @@ mstored$(EXEEXT): $(mstored_SOURCES) $(EXTRA_mstored_SOURCES)
|
|||||||
env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mstored$(EXEEXT) $(mstored_SOURCES)
|
env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mstored$(EXEEXT) $(mstored_SOURCES)
|
||||||
|
|
||||||
run: $(mstored_SOURCES)
|
run: $(mstored_SOURCES)
|
||||||
cd cmd/mstored && env CGO_ENABLED=1 $(GO) run . --asDaemon=false
|
cd cmd/mstored && env CGO_ENABLED=1 $(GO) run . --asDaemon=false --port=443
|
||||||
\
|
\
|
||||||
docs/helm-chart-manifest.json.txt \
|
docs/helm-chart-manifest.json.txt \
|
||||||
docs/mstore.drawio \
|
docs/mstore.drawio \
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ func (oper *Operator) CreateGrant(ctx context.Context, operatorID string, params
|
|||||||
err := fmt.Errorf("Grant with this right already exists")
|
err := fmt.Errorf("Grant with this right already exists")
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
oper.logg.Debugf("Call CreateGrant")
|
|
||||||
now := auxtool.TimeNow()
|
now := auxtool.TimeNow()
|
||||||
grantDescr := &descr.Grant{
|
grantDescr := &descr.Grant{
|
||||||
ID: auxuuid.NewUUID(),
|
ID: auxuuid.NewUUID(),
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func NewConfig() *Config {
|
|||||||
logfile := fmt.Sprintf("%s.log", srvname)
|
logfile := fmt.Sprintf("%s.log", srvname)
|
||||||
logpath := filepath.Join(logdir, logfile)
|
logpath := filepath.Join(logdir, logfile)
|
||||||
|
|
||||||
runfile := fmt.Sprintf("%s.run", srvname)
|
runfile := fmt.Sprintf("%s.pid", srvname)
|
||||||
runpath := filepath.Join(rundir, runfile)
|
runpath := filepath.Join(rundir, runfile)
|
||||||
|
|
||||||
//certpath := fmt.Sprintf("%s.crt", srvname)
|
//certpath := fmt.Sprintf("%s.crt", srvname)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
const (
|
const (
|
||||||
confdir = "/home/ziggi/Projects/mstore/etc/mstore"
|
confdir = "/etc/mstore"
|
||||||
rundir = "/home/ziggi/Projects/mstore/tmp/run"
|
rundir = "/var/run/mstore"
|
||||||
logdir = "/home/ziggi/Projects/mstore/tmp/log"
|
logdir = "/var/log/mstore"
|
||||||
datadir = "/home/ziggi/Projects/mstore/tmp/data"
|
datadir = "/var/lib/mstore"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
srvname = "mstored"
|
srvname = "mstored"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ func (oper *Operator) GetFile(ctx context.Context, operatorID string, params *Ge
|
|||||||
for _, descr := range fileDescrs {
|
for _, descr := range fileDescrs {
|
||||||
if descr.Type == hcMediaType {
|
if descr.Type == hcMediaType {
|
||||||
meta := &chart.Metadata{}
|
meta := &chart.Metadata{}
|
||||||
oper.logg.Debugf("=== %s", descr.HelmMeta)
|
|
||||||
err = json.Unmarshal([]byte(descr.HelmMeta), meta)
|
err = json.Unmarshal([]byte(descr.HelmMeta), meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
code := http.StatusInternalServerError
|
code := http.StatusInternalServerError
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func (hand *Handler) CheckAccess(rctx *router.Context) (bool, string, error) {
|
|||||||
|
|
||||||
//hand.logg.Debugf("URL: %s", rctx.URL().String())
|
//hand.logg.Debugf("URL: %s", rctx.URL().String())
|
||||||
authHeader := rctx.GetHeader("Authorization")
|
authHeader := rctx.GetHeader("Authorization")
|
||||||
hand.logg.Debugf("Authorization: %s", authHeader)
|
hand.logg.Debugf("Authorization: [%s]", authHeader)
|
||||||
if authHeader != "" {
|
if authHeader != "" {
|
||||||
username, password, err = auxhttp.ParseBasicAuth(authHeader)
|
username, password, err = auxhttp.ParseBasicAuth(authHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ func (hand *Handler) BlobExists(rctx *router.Context) {
|
|||||||
digest, _ := rctx.GetSubpath("digest")
|
digest, _ := rctx.GetSubpath("digest")
|
||||||
|
|
||||||
//hand.DumpHeaders("BlobExists", rctx)
|
//hand.DumpHeaders("BlobExists", rctx)
|
||||||
|
|
||||||
params := &imageoper.BlobExistsParams{
|
params := &imageoper.BlobExistsParams{
|
||||||
Name: name,
|
Name: name,
|
||||||
Digest: digest,
|
Digest: digest,
|
||||||
@@ -63,7 +62,6 @@ func (hand *Handler) PostUpload(rctx *router.Context) {
|
|||||||
name, _ := rctx.GetSubpath("name")
|
name, _ := rctx.GetSubpath("name")
|
||||||
|
|
||||||
//hand.DumpHeaders("PostUploads", rctx)
|
//hand.DumpHeaders("PostUploads", rctx)
|
||||||
|
|
||||||
authorization := rctx.GetHeader("Authorization")
|
authorization := rctx.GetHeader("Authorization")
|
||||||
if authorization == "" {
|
if authorization == "" {
|
||||||
rctx.SetHeader("WWW-Authenticate", `Basic realm="mstore"`)
|
rctx.SetHeader("WWW-Authenticate", `Basic realm="mstore"`)
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ type BlobExistsResult struct {
|
|||||||
DockerContentDigest string
|
DockerContentDigest string
|
||||||
ContentLength string
|
ContentLength string
|
||||||
ContentType string
|
ContentType string
|
||||||
//Exists bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oper *Operator) BlobExists(ctx context.Context, operatorID string, params *BlobExistsParams) (*BlobExistsResult, int, error) {
|
func (oper *Operator) BlobExists(ctx context.Context, operatorID string, params *BlobExistsParams) (*BlobExistsResult, int, error) {
|
||||||
@@ -45,7 +44,7 @@ func (oper *Operator) BlobExists(ctx context.Context, operatorID string, params
|
|||||||
defer oper.iLock.Done(resName)
|
defer oper.iLock.Done(resName)
|
||||||
|
|
||||||
// Check blob descriptor
|
// Check blob descriptor
|
||||||
descrExists, blobDescr, err := oper.mdb.GetBlobByNameDigest(ctx, params.Digest, params.Digest)
|
descrExists, blobDescr, err := oper.mdb.GetBlobByNameDigest(ctx, params.Name, params.Digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, http.StatusInternalServerError, err
|
return res, http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ func (oper *Operator) GetManifest(ctx context.Context, params *GetManifestParams
|
|||||||
|
|
||||||
manDescr := descr.Manifest{}
|
manDescr := descr.Manifest{}
|
||||||
var exists bool
|
var exists bool
|
||||||
digobj, err := ocidigest.Parse(params.Reference)
|
digobj, parseErr := ocidigest.Parse(params.Reference)
|
||||||
if err == nil {
|
if parseErr == nil {
|
||||||
exists, manDescr, err = oper.mdb.GetManifestByDigest(ctx, params.Name, digobj.String())
|
exists, manDescr, err = oper.mdb.GetManifestByDigest(ctx, params.Name, digobj.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, http.StatusInternalServerError, err
|
return res, http.StatusInternalServerError, err
|
||||||
@@ -75,6 +75,7 @@ func (oper *Operator) GetManifest(ctx context.Context, params *GetManifestParams
|
|||||||
return res, http.StatusNotFound, err
|
return res, http.StatusNotFound, err
|
||||||
}
|
}
|
||||||
if len(manDescrs) == 1 {
|
if len(manDescrs) == 1 {
|
||||||
|
manDescr = manDescrs[0]
|
||||||
res.DockerContentDigest = manDescr.Digest
|
res.DockerContentDigest = manDescr.Digest
|
||||||
size := int64(len(manDescr.Payload))
|
size := int64(len(manDescr.Payload))
|
||||||
res.ContentLength = strconv.FormatInt(size, 10)
|
res.ContentLength = strconv.FormatInt(size, 10)
|
||||||
@@ -85,8 +86,9 @@ func (oper *Operator) GetManifest(ctx context.Context, params *GetManifestParams
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, http.StatusInternalServerError, err
|
return res, http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
digobj := ocidigest.SHA256.FromBytes(indexdata)
|
digobj := ocidigest.FromBytes(indexdata)
|
||||||
res.DockerContentDigest = digobj.String()
|
res.DockerContentDigest = digobj.String()
|
||||||
|
|
||||||
size := int64(len(indexdata))
|
size := int64(len(indexdata))
|
||||||
res.ContentLength = strconv.FormatInt(size, 10)
|
res.ContentLength = strconv.FormatInt(size, 10)
|
||||||
res.ContentType = oiiMediaType
|
res.ContentType = oiiMediaType
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
//"mstore/pkg/auxoci"
|
|
||||||
"mstore/pkg/descr"
|
"mstore/pkg/descr"
|
||||||
|
|
||||||
ocidigest "github.com/opencontainers/go-digest"
|
ocidigest "github.com/opencontainers/go-digest"
|
||||||
@@ -48,8 +47,8 @@ func (oper *Operator) ManifestExists(ctx context.Context, params *ManifestExists
|
|||||||
var man descr.Manifest
|
var man descr.Manifest
|
||||||
var exist bool
|
var exist bool
|
||||||
|
|
||||||
digobj, err := ocidigest.Parse(params.Reference)
|
digobj, parseErr := ocidigest.Parse(params.Reference)
|
||||||
if err == nil {
|
if parseErr == nil {
|
||||||
exist, man, err = oper.mdb.GetManifestByDigest(ctx, params.Name, digobj.String())
|
exist, man, err = oper.mdb.GetManifestByDigest(ctx, params.Name, digobj.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, http.StatusInternalServerError, err
|
return res, http.StatusInternalServerError, err
|
||||||
@@ -75,7 +74,7 @@ func (oper *Operator) ManifestExists(ctx context.Context, params *ManifestExists
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, http.StatusInternalServerError, err
|
return res, http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
digobj := ocidigest.SHA256.FromBytes(indexdata)
|
digobj := ocidigest.FromBytes(indexdata)
|
||||||
res.DockerContentDigest = digobj.String()
|
res.DockerContentDigest = digobj.String()
|
||||||
size := int64(len(indexdata))
|
size := int64(len(indexdata))
|
||||||
res.ContentLength = strconv.FormatInt(size, 10)
|
res.ContentLength = strconv.FormatInt(size, 10)
|
||||||
|
|||||||
+10
-1
@@ -19,6 +19,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
ocidigest "github.com/opencontainers/go-digest"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,6 +75,14 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams
|
|||||||
return res, http.StatusInternalServerError, err
|
return res, http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
inManData := buffer.Bytes()
|
inManData := buffer.Bytes()
|
||||||
|
var digstr string
|
||||||
|
digobj, parseErr := ocidigest.Parse(params.Reference)
|
||||||
|
if parseErr == nil {
|
||||||
|
digstr = digobj.String()
|
||||||
|
} else {
|
||||||
|
digobj := ocidigest.FromBytes(inManData)
|
||||||
|
digstr = digobj.String()
|
||||||
|
}
|
||||||
if int64(len(inManData)) != contentLength {
|
if int64(len(inManData)) != contentLength {
|
||||||
err = fmt.Errorf("Mismatch Content-Length and received manifest size: %d vs %d",
|
err = fmt.Errorf("Mismatch Content-Length and received manifest size: %d vs %d",
|
||||||
contentLength, len(inManData))
|
contentLength, len(inManData))
|
||||||
@@ -112,6 +121,7 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams
|
|||||||
}
|
}
|
||||||
|
|
||||||
inManDescr, inlayerdescrs, err := descrsFromManifest(name, reference, inMan, inManData)
|
inManDescr, inlayerdescrs, err := descrsFromManifest(name, reference, inMan, inManData)
|
||||||
|
inManDescr.Digest = digstr
|
||||||
// Always check layer files for availability
|
// Always check layer files for availability
|
||||||
var blobError error
|
var blobError error
|
||||||
for _, blobDescr := range inlayerdescrs {
|
for _, blobDescr := range inlayerdescrs {
|
||||||
@@ -178,7 +188,6 @@ func (oper *Operator) PutManifest(ctx context.Context, params *PutManifestParams
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, blobDescr := range inlayerdescrs {
|
for _, blobDescr := range inlayerdescrs {
|
||||||
// TODO: move the requests to db layer transaction
|
// TODO: move the requests to db layer transaction
|
||||||
blobDescrExists, _, err := oper.mdb.GetBlobByNameDigest(ctx, blobDescr.Name, blobDescr.Digest)
|
blobDescrExists, _, err := oper.mdb.GetBlobByNameDigest(ctx, blobDescr.Name, blobDescr.Digest)
|
||||||
|
|||||||
@@ -21,14 +21,14 @@ import (
|
|||||||
|
|
||||||
type Database struct {
|
type Database struct {
|
||||||
datapath string
|
datapath string
|
||||||
log *logger.Logger
|
logg *logger.Logger
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDatabase(datapath string) *Database {
|
func NewDatabase(datapath string) *Database {
|
||||||
return &Database{
|
return &Database{
|
||||||
datapath: datapath,
|
datapath: datapath,
|
||||||
log: logger.NewLoggerWithSubject("maindb"),
|
logg: logger.NewLoggerWithSubject("maindb"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ func (srv *Server) SetAsDaemon(asDaemon bool) {
|
|||||||
|
|
||||||
func (srv *Server) Configure() error {
|
func (srv *Server) Configure() error {
|
||||||
var err error
|
var err error
|
||||||
srv.logg.Infof("Configuration server")
|
//srv.logg.Infof("Configuration server")
|
||||||
srv.conf = config.NewConfig()
|
srv.conf = config.NewConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ func (svc *Service) Build() error {
|
|||||||
svc.rout.Use(router.NewCorsMiddleware())
|
svc.rout.Use(router.NewCorsMiddleware())
|
||||||
svc.rout.Use(svc.hand.AuthMiddleware)
|
svc.rout.Use(svc.hand.AuthMiddleware)
|
||||||
|
|
||||||
|
svc.rout.Head(`/v2/{name}/blobs/{digest}`, svc.hand.BlobExists)
|
||||||
|
|
||||||
svc.rout.Get(`/v3/api/service/hello`, svc.hand.SendHello)
|
svc.rout.Get(`/v3/api/service/hello`, svc.hand.SendHello)
|
||||||
|
|
||||||
svc.rout.Head(`/v3/api/file/{filepath}`, svc.hand.FileInfo)
|
svc.rout.Head(`/v3/api/file/{filepath}`, svc.hand.FileInfo)
|
||||||
@@ -93,8 +95,6 @@ func (svc *Service) Build() error {
|
|||||||
svc.rout.Get(`/v2/{name}/manifests/{reference}`, svc.hand.GetManifest)
|
svc.rout.Get(`/v2/{name}/manifests/{reference}`, svc.hand.GetManifest)
|
||||||
svc.rout.Delete(`/v2/{name}/manifests/{reference}`, svc.hand.DeleteManifest)
|
svc.rout.Delete(`/v2/{name}/manifests/{reference}`, svc.hand.DeleteManifest)
|
||||||
|
|
||||||
svc.rout.Head(`/v2/{name}/blobs/{digest}`, svc.hand.BlobExists)
|
|
||||||
|
|
||||||
svc.rout.Post(`/v2/{name}/blobs/uploads/`, svc.hand.PostUpload)
|
svc.rout.Post(`/v2/{name}/blobs/uploads/`, svc.hand.PostUpload)
|
||||||
svc.rout.Patch(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PatchUpload)
|
svc.rout.Patch(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PatchUpload)
|
||||||
svc.rout.Put(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PutUpload)
|
svc.rout.Put(`/v2/{name}/blobs/uploads/{reference}`, svc.hand.PutUpload)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ func (util *ImageUtil) catalogImages(common *CommonImageParams, params *CatalogI
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
ref.SetUserinfo(common.Username, common.Password)
|
||||||
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
||||||
cli := repocli.NewClient(nil, mw)
|
cli := repocli.NewClient(nil, mw)
|
||||||
opres, err := cli.GetCatalog(ctx, ref.Raw())
|
opres, err := cli.GetCatalog(ctx, ref.Raw())
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ func (util *ImageUtil) deleteImage(common *CommonImageParams, params *DeleteImag
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
ref.SetUserinfo(common.Username, common.Password)
|
||||||
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
||||||
cli := repocli.NewClient(nil, mw)
|
cli := repocli.NewClient(nil, mw)
|
||||||
_, err = cli.DeleteImage(ctx, ref.Raw())
|
_, err = cli.DeleteImage(ctx, ref.Raw())
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
|
||||||
*
|
|
||||||
* This work is published and licensed under a Creative Commons
|
|
||||||
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
|
||||||
*
|
|
||||||
* Distribution of this work is permitted, but commercial use and
|
|
||||||
* modifications are strictly prohibited.
|
|
||||||
*/
|
|
||||||
package imagecmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
"mstore/pkg/gcrcli"
|
|
||||||
|
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ImageConfig
|
|
||||||
type ImageConfigParams struct {
|
|
||||||
Imagepath string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ImageConfigResult struct {
|
|
||||||
ImageConfig *ocispec.Image `json:"imageConfig"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (util *ImageUtil) ImageConfig(cmd *cobra.Command, args []string) {
|
|
||||||
util.imageConfigParams.Imagepath = args[0]
|
|
||||||
res, err := util.imageConfig(&util.commonImageParams, &util.imageConfigParams)
|
|
||||||
printResponse(res, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (util *ImageUtil) imageConfig(common *CommonImageParams, params *ImageConfigParams) (*ImageConfigResult, error) {
|
|
||||||
var err error
|
|
||||||
res := &ImageConfigResult{
|
|
||||||
ImageConfig: &ocispec.Image{},
|
|
||||||
}
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
cli := gcrcli.NewClient(common.SkipTLSVerify)
|
|
||||||
timeout := time.Duration(common.Timeout) * time.Second
|
|
||||||
|
|
||||||
params.Imagepath, err = packUserinfo(params.Imagepath, common.Username, common.Password)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
|
||||||
opres, err := cli.ImageConfig(ctx, params.Imagepath)
|
|
||||||
if err != nil {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
res.ImageConfig = opres
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
@@ -102,14 +102,6 @@ func (util *ImageUtil) CreateImageCmds() *cobra.Command {
|
|||||||
}
|
}
|
||||||
subCmd.AddCommand(imageTagsCmd)
|
subCmd.AddCommand(imageTagsCmd)
|
||||||
|
|
||||||
// ImageConfig
|
|
||||||
var imageConfigCmd = &cobra.Command{
|
|
||||||
Use: "config [user:pass@]hostname[:port]/path:tag",
|
|
||||||
Short: "Show container image config info",
|
|
||||||
Args: cobra.ExactArgs(1),
|
|
||||||
Run: util.ImageConfig,
|
|
||||||
}
|
|
||||||
subCmd.AddCommand(imageConfigCmd)
|
|
||||||
// CatalogImages
|
// CatalogImages
|
||||||
var catalogImagesCmd = &cobra.Command{
|
var catalogImagesCmd = &cobra.Command{
|
||||||
Use: "catalog [user:pass@]hostname[:port]",
|
Use: "catalog [user:pass@]hostname[:port]",
|
||||||
@@ -125,7 +117,6 @@ func (util *ImageUtil) CreateImageCmds() *cobra.Command {
|
|||||||
type ImageUtil struct {
|
type ImageUtil struct {
|
||||||
imageManifestParams ImageManifestParams
|
imageManifestParams ImageManifestParams
|
||||||
imageTagsParams ImageTagsParams
|
imageTagsParams ImageTagsParams
|
||||||
imageConfigParams ImageConfigParams
|
|
||||||
catalogImagesParams CatalogImagesParams
|
catalogImagesParams CatalogImagesParams
|
||||||
|
|
||||||
pullImageParams PullImageParams
|
pullImageParams PullImageParams
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ func (util *ImageUtil) imageManifest(common *CommonImageParams, params *ImageMan
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
ref.SetUserinfo(common.Username, common.Password)
|
||||||
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
||||||
cli := repocli.NewClient(nil, mw)
|
cli := repocli.NewClient(nil, mw)
|
||||||
exists, mime, man, _, err := cli.GetRawManifest(ctx, ref.RawRepo())
|
exists, mime, man, _, err := cli.GetRawManifest(ctx, ref.RawRepo())
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ func (util *ImageUtil) imageTags(common *CommonImageParams, params *ImageTagsPar
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
ref.SetUserinfo(common.Username, common.Password)
|
||||||
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
||||||
cli := repocli.NewClient(nil, mw)
|
cli := repocli.NewClient(nil, mw)
|
||||||
opres, err := cli.GetTags(ctx, ref.Raw())
|
opres, err := cli.GetTags(ctx, ref.Raw())
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"mstore/pkg/auxtool"
|
||||||
|
"mstore/pkg/auxutar"
|
||||||
"mstore/pkg/gcrcli"
|
"mstore/pkg/gcrcli"
|
||||||
|
"mstore/pkg/repocli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PullImage
|
// PullImage
|
||||||
@@ -39,6 +42,45 @@ func (util *ImageUtil) PullImage(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
func (util *ImageUtil) pullImage(common *CommonImageParams, params *PullImageParams) (*PullImageResult, error) {
|
func (util *ImageUtil) pullImage(common *CommonImageParams, params *PullImageParams) (*PullImageResult, error) {
|
||||||
var err error
|
var err error
|
||||||
|
res := &PullImageResult{}
|
||||||
|
|
||||||
|
timeout := time.Duration(common.Timeout) * time.Second
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), timeout)
|
||||||
|
|
||||||
|
ref, err := repocli.NewReferer(params.Imagepath)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
ref.SetUserinfo(common.Username, common.Password)
|
||||||
|
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
||||||
|
cli := repocli.NewClient(nil, mw)
|
||||||
|
load := repocli.NewLoader(cli)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
imageDir := auxtool.MakeTmpFilename(params.Filepath)
|
||||||
|
err = load.Pull(ctx, ref.Raw(), imageDir, "", "")
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
err = auxutar.Archive(imageDir, params.Filepath)
|
||||||
|
defer os.RemoveAll(imageDir)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
filestat, err := os.Stat(params.Filepath)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res.Size = filestat.Size()
|
||||||
|
res.Filepath = params.Filepath
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (util *ImageUtil) XXXpullImage(common *CommonImageParams, params *PullImageParams) (*PullImageResult, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res := &PullImageResult{}
|
res := &PullImageResult{}
|
||||||
@@ -60,6 +102,5 @@ func (util *ImageUtil) pullImage(common *CommonImageParams, params *PullImagePar
|
|||||||
}
|
}
|
||||||
res.Size = filestat.Size()
|
res.Size = filestat.Size()
|
||||||
res.Filepath = params.Filepath
|
res.Filepath = params.Filepath
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
@@ -11,11 +11,15 @@ package imagecmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"mstore/pkg/auxtool"
|
||||||
|
"mstore/pkg/auxutar"
|
||||||
"mstore/pkg/gcrcli"
|
"mstore/pkg/gcrcli"
|
||||||
|
"mstore/pkg/repocli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PushImage
|
// PushImage
|
||||||
@@ -35,6 +39,36 @@ func (util *ImageUtil) PushImage(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (util *ImageUtil) pushImage(common *CommonImageParams, params *PushImageParams) (*PushImageResult, error) {
|
func (util *ImageUtil) pushImage(common *CommonImageParams, params *PushImageParams) (*PushImageResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &PushImageResult{}
|
||||||
|
|
||||||
|
timeout := time.Duration(common.Timeout) * time.Second
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), timeout)
|
||||||
|
|
||||||
|
ref, err := repocli.NewReferer(params.Imagepath)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
ref.SetUserinfo(common.Username, common.Password)
|
||||||
|
mw := repocli.NewBasicAuthMiddleware(ref.Userinfo())
|
||||||
|
cli := repocli.NewClient(nil, mw)
|
||||||
|
load := repocli.NewLoader(cli)
|
||||||
|
|
||||||
|
imageDir := auxtool.MakeTmpFilename(params.Filepath)
|
||||||
|
err = auxutar.Unarchive(params.Filepath, imageDir)
|
||||||
|
defer os.RemoveAll(imageDir)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
err = load.Push(ctx, imageDir, ref.Raw(), "", "")
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (util *ImageUtil) XXXpushImage(common *CommonImageParams, params *PushImageParams) (*PushImageResult, error) {
|
||||||
var err error
|
var err error
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
res := &PushImageResult{}
|
res := &PushImageResult{}
|
||||||
@@ -3826,7 +3826,7 @@ printf "%s\n" "$as_me: srv_libdir set as ${SRV_LIBDIR}" >&6;}
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
SRV_DATADIR="/var/data/${PACKAGE}"
|
SRV_DATADIR="/var/lib/${PACKAGE}"
|
||||||
|
|
||||||
|
|
||||||
# Check whether --with-datadir was given.
|
# Check whether --with-datadir was given.
|
||||||
|
|||||||
+1
-1
@@ -213,7 +213,7 @@ AC_MSG_NOTICE(srv_libdir set as ${SRV_LIBDIR})
|
|||||||
dnl --------------------------------------------------------------------------------------
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
SRV_DATADIR="/var/data/${PACKAGE}"
|
SRV_DATADIR="/var/lib/${PACKAGE}"
|
||||||
|
|
||||||
AC_ARG_WITH(datadir,
|
AC_ARG_WITH(datadir,
|
||||||
AS_HELP_STRING([--with-datadir=PATH],[set path for datadir (default: $SRV_DATADIR)]),
|
AS_HELP_STRING([--with-datadir=PATH],[set path for datadir (default: $SRV_DATADIR)]),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Description=mstored
|
|||||||
[Service]
|
[Service]
|
||||||
Type=forking
|
Type=forking
|
||||||
PIDFile=@srv_rundir@/mstored.pid
|
PIDFile=@srv_rundir@/mstored.pid
|
||||||
ExecStart=@prefix@/sbin/mstored -daemon=true
|
ExecStart=@prefix@/sbin/mstored --asDaemon=true --port=443
|
||||||
ExecReload=/bin/kill -HUP $MAINPID
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|||||||
+31
-31
@@ -30,7 +30,7 @@ type Referer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ParsePath(rawpath string) (*Referer, error) {
|
func ParsePath(rawpath string) (*Referer, error) {
|
||||||
repo := &Referer{
|
ref := &Referer{
|
||||||
values: url.Values{},
|
values: url.Values{},
|
||||||
}
|
}
|
||||||
if !strings.Contains(rawpath, "://") {
|
if !strings.Contains(rawpath, "://") {
|
||||||
@@ -38,71 +38,71 @@ func ParsePath(rawpath string) (*Referer, error) {
|
|||||||
}
|
}
|
||||||
urlobj, err := url.Parse(rawpath)
|
urlobj, err := url.Parse(rawpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo, err
|
return ref, err
|
||||||
}
|
}
|
||||||
if urlobj.User != nil {
|
if urlobj.User != nil {
|
||||||
repo.user = urlobj.User.Username()
|
ref.user = urlobj.User.Username()
|
||||||
repo.pass, _ = urlobj.User.Password()
|
ref.pass, _ = urlobj.User.Password()
|
||||||
urlobj.User = nil
|
urlobj.User = nil
|
||||||
}
|
}
|
||||||
repo.resource = path.Join("/", urlobj.Path)
|
ref.resource = path.Join("/", urlobj.Path)
|
||||||
urlobj.Path = "/"
|
urlobj.Path = "/"
|
||||||
repo.urlobj = urlobj
|
ref.urlobj = urlobj
|
||||||
repo.values = urlobj.Query()
|
ref.values = urlobj.Query()
|
||||||
return repo, err
|
return ref, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) Raw() string {
|
func (ref *Referer) Raw() string {
|
||||||
res := path.Join(repo.urlobj.Host, repo.resource)
|
res := path.Join(ref.urlobj.Host, ref.resource)
|
||||||
query := repo.values.Encode()
|
query := ref.values.Encode()
|
||||||
if query != "" {
|
if query != "" {
|
||||||
return res + "?" + query
|
return res + "?" + query
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) SetResource(resource string) {
|
func (ref *Referer) SetResource(resource string) {
|
||||||
repo.resource = path.Join("/", resource)
|
ref.resource = path.Join("/", resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) JoinResource(resource string) {
|
func (ref *Referer) JoinResource(resource string) {
|
||||||
repo.resource = path.Join("/", repo.resource, resource)
|
ref.resource = path.Join("/", ref.resource, resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) PathType(typ string) {
|
func (ref *Referer) PathType(typ string) {
|
||||||
repo.values.Set("pathType", typ)
|
ref.values.Set("pathType", typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) DryRun(yesno bool) {
|
func (ref *Referer) DryRun(yesno bool) {
|
||||||
repo.values.Set("dryRun", strconv.FormatBool(yesno))
|
ref.values.Set("dryRun", strconv.FormatBool(yesno))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) FileEP() string {
|
func (ref *Referer) FileEP() string {
|
||||||
curl := repo.urlobj.JoinPath("/v3/api/file/", repo.resource)
|
curl := ref.urlobj.JoinPath("/v3/api/file/", ref.resource)
|
||||||
return curl.String()
|
return curl.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) FilesEP() string {
|
func (ref *Referer) FilesEP() string {
|
||||||
curl := repo.urlobj.JoinPath("/v3/api/files/", repo.resource)
|
curl := ref.urlobj.JoinPath("/v3/api/files/", ref.resource)
|
||||||
return curl.String()
|
return curl.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) CollectionEP() string {
|
func (ref *Referer) CollectionEP() string {
|
||||||
curl := repo.urlobj.JoinPath("/v3/api/collection/", repo.resource)
|
curl := ref.urlobj.JoinPath("/v3/api/collection/", ref.resource)
|
||||||
return curl.String()
|
return curl.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) CollectionsEP() string {
|
func (ref *Referer) CollectionsEP() string {
|
||||||
curl := repo.urlobj.JoinPath("/v3/api/collections/", repo.resource)
|
curl := ref.urlobj.JoinPath("/v3/api/collections/", ref.resource)
|
||||||
return curl.String()
|
return curl.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) Userinfo() (string, string) {
|
func (ref *Referer) Userinfo() (string, string) {
|
||||||
return repo.user, repo.pass
|
return ref.user, ref.pass
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Referer) SetUserinfo(user, pass string) {
|
func (ref *Referer) SetUserinfo(user, pass string) {
|
||||||
if user != "" && pass != "" {
|
if user != "" && pass != "" {
|
||||||
repo.user, repo.pass = user, pass
|
ref.user, ref.pass = user, pass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ func (cli *Client) BlobExists(ctx context.Context, rawrepo string, digest string
|
|||||||
return exist, size, err
|
return exist, size, err
|
||||||
}
|
}
|
||||||
uri := ref.BlobEP(digest)
|
uri := ref.BlobEP(digest)
|
||||||
|
|
||||||
fmt.Println(uri)
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodHead, uri, nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodHead, uri, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return exist, size, err
|
return exist, size, err
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (down *Loader) Push(ctx context.Context, rawref, dir, osname, arch string) error {
|
func (down *Loader) Push(ctx context.Context, dir, rawref, osname, arch string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ref, err := NewReferer(rawref)
|
ref, err := NewReferer(rawref)
|
||||||
@@ -45,11 +45,16 @@ func (down *Loader) Push(ctx context.Context, rawref, dir, osname, arch string)
|
|||||||
layers = append(layers, man.Layers...)
|
layers = append(layers, man.Layers...)
|
||||||
layers = append(layers, man.Config)
|
layers = append(layers, man.Config)
|
||||||
for _, layer := range layers {
|
for _, layer := range layers {
|
||||||
|
digstr := layer.Digest.String()
|
||||||
|
exists, _, err := down.cli.BlobExists(ctx, ref.RawRepo(), digstr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
id, _, err := down.cli.GetUpload(ctx, ref.RawRepo())
|
id, _, err := down.cli.GetUpload(ctx, ref.RawRepo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
digstr := layer.Digest.String()
|
|
||||||
size, reader, err := imager.LayerReader(ctx, digstr)
|
size, reader, err := imager.LayerReader(ctx, digstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -64,6 +69,7 @@ func (down *Loader) Push(ctx context.Context, rawref, dir, osname, arch string)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
err = down.cli.PutManifest(ctx, ref.Raw(), mandata, mime)
|
err = down.cli.PutManifest(ctx, ref.Raw(), mandata, mime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func TestPushImage(t *testing.T) {
|
|||||||
load := NewLoader(cli)
|
load := NewLoader(cli)
|
||||||
require.NotNil(t, load)
|
require.NotNil(t, load)
|
||||||
|
|
||||||
err := load.Push(ctx, "localhost:1025/test:v1.0", "test-oci", "", "")
|
err := load.Push(ctx, "test-oci", "localhost:1025/test:v1.0", "", "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
//return
|
//return
|
||||||
|
|||||||
@@ -144,3 +144,9 @@ func (ref *Referer) CatalogEP() string {
|
|||||||
func (ref *Referer) Userinfo() (string, string) {
|
func (ref *Referer) Userinfo() (string, string) {
|
||||||
return ref.user, ref.pass
|
return ref.user, ref.pass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ref *Referer) SetUserinfo(user, pass string) {
|
||||||
|
if user != "" && pass != "" {
|
||||||
|
ref.user, ref.pass = user, pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user