From 8a566e5dae1c253c5a52ae80327d054499f87e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3=20=D0=91=D0=BE=D1=80=D0=BE=D0=B4?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 2 Feb 2026 18:11:25 +0200 Subject: [PATCH] working commit --- .gitignore | 1 + pkg/client/imageinfo.go | 114 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 pkg/client/imageinfo.go diff --git a/.gitignore b/.gitignore index c7aa303..0308945 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ cmd/mstorectl/mstorectl *.tmp.* *.tar *.bin +tmp diff --git a/pkg/client/imageinfo.go b/pkg/client/imageinfo.go new file mode 100644 index 0000000..92d7baf --- /dev/null +++ b/pkg/client/imageinfo.go @@ -0,0 +1,114 @@ +package client + +import ( + "context" + "time" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" + pkg "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" +) + +type ImageDescr struct { + ConfigFile *pkg.ConfigFile `json:"configFile,omitempty"` + Manifest *pkg.Manifest `json:"manifest,omitempty"` + Tags []string `json:"avilableTags,omitempty"` +} + +func (cli *Client) ImageInfo(ctx context.Context, imagepath string, timeout time.Duration) (*ImageDescr, error) { + var err error + res := &ImageDescr{} + + ctx, _ = context.WithTimeout(ctx, timeout) + + options := make([]crane.Option, 0) + options = append(options, crane.WithContext(ctx)) + + ref, err := name.ParseReference(imagepath) + if err != nil { + return res, err + } + repo := ref.Context() + if err != nil { + return res, err + } + + if cli.username != "" && cli.password != "" { + defaultTransport := &roundTripper{} + scopes := []string{repo.Scope(transport.PullScope)} + + regName := repo.RegistryStr() + reg, err := name.NewRegistry(regName) + if err != nil { + return res, err + } + basicAuth := &authn.Basic{ + Username: cli.username, + Password: cli.password, + } + authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes) + if err != nil { + return res, err + } + options = append(options, crane.WithTransport(authTransport)) + } else { + transport := &roundTripper{} + options = append(options, crane.WithTransport(transport)) + } + + image, err := crane.Pull(imagepath, options...) + if err != nil { + return res, err + } + + config, err := image.ConfigFile() + if err != nil { + return res, err + } + res.ConfigFile = config + + manifest, err := image.Manifest() + if err != nil { + return res, err + } + res.Manifest = manifest + + return res, err + + remoteOptions := make([]remote.Option, 0) + remoteOptions = append(remoteOptions, remote.WithContext(ctx)) + + if cli.username != "" && cli.password != "" { + defaultTransport := &roundTripper{} + scopes := []string{repo.Scope(transport.PullScope)} + + regName := repo.RegistryStr() + reg, err := name.NewRegistry(regName) + if err != nil { + return res, err + } + basicAuth := &authn.Basic{ + Username: cli.username, + Password: cli.password, + } + authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes) + if err != nil { + return res, err + } + remoteOptions = append(remoteOptions, remote.WithTransport(authTransport)) + } else { + transport := &roundTripper{} + options = append(options, crane.WithTransport(transport)) + } + + tags, err := remote.List(repo, remoteOptions...) + if err != nil { + return res, err + } + res.Tags = tags + + return res, err +}