diff --git a/cmd/mstorectl/imagecmd.go b/cmd/mstorectl/imagecmd.go index d8f12ea..741d09d 100644 --- a/cmd/mstorectl/imagecmd.go +++ b/cmd/mstorectl/imagecmd.go @@ -1,6 +1,8 @@ package main import ( + "mstore/pkg/client" + "github.com/spf13/cobra" ) @@ -74,7 +76,7 @@ type ImageInfoParams struct { } type ImageInfoResult struct { - ImageInfo ImageDescr `json:"imageInfo"` + ImageInfo *client.ImageDescr `json:"imageInfo"` } func (util *ImageUtil) ImageInfo(cmd *cobra.Command, args []string) { diff --git a/cmd/mstorectl/imageinfo.go b/cmd/mstorectl/imageinfo.go index 3e71c75..0925505 100644 --- a/cmd/mstorectl/imageinfo.go +++ b/cmd/mstorectl/imageinfo.go @@ -4,111 +4,18 @@ 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" + "mstore/pkg/client" ) -type ImageDescr struct { - ConfigFile *pkg.ConfigFile `json:"configFile,omitempty"` - Manifest *pkg.Manifest `json:"manifest,omitempty"` - Tags []string `json:"avilableTags,omitempty"` -} - func (util *ImageUtil) imageInfo(params *ImageInfoParams) (*ImageInfoResult, error) { var err error res := &ImageInfoResult{} + ctx := context.Background() - ctx, _ := context.WithTimeout(context.Background(), time.Duration(params.Timeout)*time.Second) - - options := make([]crane.Option, 0) - options = append(options, crane.WithContext(ctx)) - - ref, err := name.ParseReference(params.Imagepath) - if err != nil { - return res, err - } - repo := ref.Context() - if err != nil { - return res, err - } - - if params.Username != "" && params.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: params.Username, - Password: params.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(params.Imagepath, options...) - if err != nil { - return res, err - } - - config, err := image.ConfigFile() - if err != nil { - return res, err - } - res.ImageInfo.ConfigFile = config - - manifest, err := image.Manifest() - if err != nil { - return res, err - } - res.ImageInfo.Manifest = manifest - - return res, err - - remoteOptions := make([]remote.Option, 0) - remoteOptions = append(remoteOptions, remote.WithContext(ctx)) - - if params.Username != "" && params.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: params.Username, - Password: params.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.ImageInfo.Tags = tags + cli := client.NewClientWithAuth(params.Username, params.Password) + timeout := time.Duration(params.Timeout) * time.Second + opres, err := cli.ImageInfo(ctx, params.Imagepath, timeout) + res.ImageInfo = opres return res, err } diff --git a/cmd/mstorectl/imagepull.go b/cmd/mstorectl/imagepull.go index 9f71274..6bf1a50 100644 --- a/cmd/mstorectl/imagepull.go +++ b/cmd/mstorectl/imagepull.go @@ -2,75 +2,20 @@ package main import ( "context" - "os" "time" - "github.com/google/go-containerregistry/pkg/authn" - "github.com/google/go-containerregistry/pkg/crane" - "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "mstore/pkg/client" ) func (util *ImageUtil) pullImage(params *PullImageParams) (*PullImageResult, error) { var err error - ctx, _ := context.WithTimeout(context.Background(), time.Duration(params.Timeout)*time.Second) - + ctx := context.Background() res := &PullImageResult{} - options := make([]crane.Option, 0) - options = append(options, crane.WithContext(ctx)) - if params.Username != "" && params.Password != "" { - ref, err := name.ParseReference(params.Imagepath) - if err != nil { - return res, err - } - repo := ref.Context() - if err != nil { - return res, err - } - defaultTransport := &roundTripper{} - scopes := []string{repo.Scope(transport.PullScope)} + cli := client.NewClientWithAuth(params.Username, params.Password) + timeout := time.Duration(params.Timeout) * time.Second + err = cli.PullImage(ctx, params.Imagepath, params.Filepath, timeout) - regName := repo.RegistryStr() - reg, err := name.NewRegistry(regName) - if err != nil { - return res, err - } - basicAuth := &authn.Basic{ - Username: params.Username, - Password: params.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(params.Imagepath, options...) - if err != nil { - return res, err - } - dstDir := makeTmpFileName(params.Filepath) - err = os.MkdirAll(dstDir, 0750) - if err != nil { - return res, err - } - err = crane.SaveOCI(image, dstDir) - if err != nil { - return res, err - } - err = archiveDir(dstDir, params.Filepath) - if err != nil { - return res, err - } - err = os.RemoveAll(dstDir) - if err != nil { - return res, err - } return res, err } diff --git a/cmd/mstorectl/imagepush.go b/cmd/mstorectl/imagepush.go index 9aec838..a590ebb 100644 --- a/cmd/mstorectl/imagepush.go +++ b/cmd/mstorectl/imagepush.go @@ -2,105 +2,19 @@ package main import ( "context" - "fmt" - "os" "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/layout" - "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "mstore/pkg/client" ) func (util *ImageUtil) pushImage(params *PushImageParams) (*PushImageResult, error) { var err error - ctx, _ := context.WithTimeout(context.Background(), time.Duration(params.Timeout)*time.Second) + ctx := context.Background() res := &PushImageResult{} - options := make([]crane.Option, 0) - options = append(options, crane.WithContext(ctx)) - if params.Username != "" && params.Password != "" { - ref, err := name.ParseReference(params.Imagepath) - if err != nil { - return res, err - } - repo := ref.Context() - if err != nil { - return res, err - } - defaultTransport := &roundTripper{} + cli := client.NewClientWithAuth(params.Username, params.Password) + timeout := time.Duration(params.Timeout) * time.Second + err = cli.PushImage(ctx, params.Filepath, params.Imagepath, timeout) - scopes := []string{ - repo.Scope(transport.PushScope), - repo.Scope(transport.PullScope), - } - - regName := repo.RegistryStr() - reg, err := name.NewRegistry(regName) - if err != nil { - return res, err - } - basicAuth := &authn.Basic{ - Username: params.Username, - Password: params.Password, - } - - authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, - defaultTransport, scopes) - if err != nil { - return res, err - } - options = append(options, crane.WithTransport(authTransport)) - } else { - defaultTransport := &roundTripper{} - options = append(options, crane.WithTransport(defaultTransport)) - } - - dstDir := makeTmpFileName(params.Filepath) - err = unarchive(params.Filepath, dstDir) - if err != nil { - os.RemoveAll(dstDir) - return res, err - } - image, err := imageLoader(dstDir) - if err != nil { - os.RemoveAll(dstDir) - return res, err - } - err = crane.Push(image, params.Imagepath, options...) - if err != nil { - return res, err - } - return res, err -} - -func imageLoader(dirPath string) (pkg.Image, error) { - var err error - var res pkg.Image - layoutPath, err := layout.FromPath(dirPath) - if err != nil { - return res, err - } - imageIndex, err := layoutPath.ImageIndex() - if err != nil { - return res, err - } - indexManifest, err := imageIndex.IndexManifest() - if err != nil { - return res, err - } - if indexManifest == nil { - err := fmt.Errorf("Empty indexManifest referency") - return res, err - } - - manifest := indexManifest.Manifests[0] - image, err := layoutPath.Image(manifest.Digest) - if err != nil { - return res, err - } - res = image return res, err } diff --git a/pkg/client/fileaux.go b/pkg/client/fileaux.go new file mode 100644 index 0000000..4111bd9 --- /dev/null +++ b/pkg/client/fileaux.go @@ -0,0 +1,14 @@ +package client + +import ( + "encoding/hex" + "fmt" + "math/rand" +) + +func makeTmpFileName(prefix string) string { + randBytes := make([]byte, 6) + rand.Read(randBytes) + suffix := hex.EncodeToString(randBytes) + return fmt.Sprintf("%s.tmp.%s", prefix, suffix) +} diff --git a/cmd/mstorectl/imageaux.go b/pkg/client/imageaux.go similarity index 95% rename from cmd/mstorectl/imageaux.go rename to pkg/client/imageaux.go index 016c8d0..711406f 100644 --- a/cmd/mstorectl/imageaux.go +++ b/pkg/client/imageaux.go @@ -1,4 +1,4 @@ -package main +package client import ( "crypto/tls" diff --git a/pkg/client/imagepull.go b/pkg/client/imagepull.go new file mode 100644 index 0000000..95f8dfa --- /dev/null +++ b/pkg/client/imagepull.go @@ -0,0 +1,75 @@ +package client + +import ( + "context" + "os" + "time" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/crane" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" +) + +func (cli *Client) PullImage(ctx context.Context, filepath, imagepath string, timeout time.Duration) error { + var err error + ctx, _ = context.WithTimeout(ctx, timeout) + + options := make([]crane.Option, 0) + options = append(options, crane.WithContext(ctx)) + + if cli.username != "" && cli.password != "" { + ref, err := name.ParseReference(imagepath) + if err != nil { + return err + } + repo := ref.Context() + if err != nil { + return err + } + defaultTransport := &roundTripper{} + + scopes := []string{repo.Scope(transport.PullScope)} + + regName := repo.RegistryStr() + reg, err := name.NewRegistry(regName) + if err != nil { + return err + } + basicAuth := &authn.Basic{ + Username: cli.username, + Password: cli.password, + } + authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes) + if err != nil { + return 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 err + } + dstdir := makeTmpFileName(filepath) + err = os.MkdirAll(dstdir, 0750) + if err != nil { + return err + } + err = crane.SaveOCI(image, dstdir) + if err != nil { + return err + } + err = archiveDir(dstdir, filepath) + if err != nil { + return err + } + err = os.RemoveAll(dstdir) + if err != nil { + return err + } + return err +} diff --git a/pkg/client/imagepush.go b/pkg/client/imagepush.go new file mode 100644 index 0000000..c8c707a --- /dev/null +++ b/pkg/client/imagepush.go @@ -0,0 +1,104 @@ +package client + +import ( + "context" + "fmt" + "os" + "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/layout" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" +) + +func (cli *Client) PushImage(ctx context.Context, filepath, imagepath string, timeout time.Duration) error { + var err error + ctx, _ = context.WithTimeout(ctx, timeout) + + options := make([]crane.Option, 0) + options = append(options, crane.WithContext(ctx)) + if cli.username != "" && cli.password != "" { + ref, err := name.ParseReference(imagepath) + if err != nil { + return err + } + repo := ref.Context() + if err != nil { + return err + } + defaultTransport := &roundTripper{} + + scopes := []string{ + repo.Scope(transport.PushScope), + repo.Scope(transport.PullScope), + } + + regName := repo.RegistryStr() + reg, err := name.NewRegistry(regName) + if err != nil { + return err + } + basicAuth := &authn.Basic{ + Username: cli.username, + Password: cli.password, + } + + authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes) + if err != nil { + return err + } + options = append(options, crane.WithTransport(authTransport)) + } else { + defaultTransport := &roundTripper{} + options = append(options, crane.WithTransport(defaultTransport)) + } + + dstdir := makeTmpFileName(filepath) + err = unarchive(filepath, dstdir) + if err != nil { + os.RemoveAll(dstdir) + return err + } + image, err := imageLoader(dstdir) + if err != nil { + os.RemoveAll(dstdir) + return err + } + err = crane.Push(image, imagepath, options...) + if err != nil { + return err + } + return err +} + +func imageLoader(dirPath string) (pkg.Image, error) { + var err error + var res pkg.Image + layoutPath, err := layout.FromPath(dirPath) + if err != nil { + return res, err + } + imageIndex, err := layoutPath.ImageIndex() + if err != nil { + return res, err + } + indexManifest, err := imageIndex.IndexManifest() + if err != nil { + return res, err + } + if indexManifest == nil { + err := fmt.Errorf("Empty indexManifest referency") + return res, err + } + + manifest := indexManifest.Manifests[0] + image, err := layoutPath.Image(manifest.Digest) + if err != nil { + return res, err + } + res = image + return res, err +} diff --git a/cmd/mstorectl/taraux.go b/pkg/client/taraux.go similarity index 89% rename from cmd/mstorectl/taraux.go rename to pkg/client/taraux.go index 1e9b177..ebaca39 100644 --- a/cmd/mstorectl/taraux.go +++ b/pkg/client/taraux.go @@ -1,11 +1,8 @@ -package main +package client import ( "archive/tar" - "encoding/hex" - "fmt" "io" - "math/rand" "os" "path/filepath" "strings" @@ -78,7 +75,6 @@ func unarchive(filePath, dstDir string) error { defer file.Close() tarReader := tar.NewReader(file) - //defer tarReader.Close() for { header, err := tarReader.Next() switch { @@ -120,10 +116,3 @@ func unarchive(filePath, dstDir string) error { } return err } - -func makeTmpFileName(prefix string) string { - randBytes := make([]byte, 6) - rand.Read(randBytes) - suffix := hex.EncodeToString(randBytes) - return fmt.Sprintf("%s.tmp.%s", prefix, suffix) -}