From 6872aebe57197ba2a2154d5083be91a441103157 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: Thu, 29 Jan 2026 15:22:15 +0200 Subject: [PATCH] working commit --- cmd/mstorectl/filecmd.go | 112 ++++++++++++++++++++++++++++++++ cmd/mstorectl/imageaux.go | 18 ++++++ cmd/mstorectl/imagecmd.go | 115 +++++++++++++++++++++++++++++++++ cmd/mstorectl/imageinfo.go | 114 ++++++++++++++++++++++++++++++++ cmd/mstorectl/imagepull.go | 76 ++++++++++++++++++++++ cmd/mstorectl/imagepush.go | 106 ++++++++++++++++++++++++++++++ cmd/mstorectl/main.go | 7 +- cmd/mstorectl/taraux.go | 129 +++++++++++++++++++++++++++++++++++++ cmd/mstored/main.go | 43 +++++++++++++ 9 files changed, 718 insertions(+), 2 deletions(-) create mode 100644 cmd/mstorectl/filecmd.go create mode 100644 cmd/mstorectl/imageaux.go create mode 100644 cmd/mstorectl/imagecmd.go create mode 100644 cmd/mstorectl/imageinfo.go create mode 100644 cmd/mstorectl/imagepull.go create mode 100644 cmd/mstorectl/imagepush.go create mode 100644 cmd/mstorectl/taraux.go create mode 100644 cmd/mstored/main.go diff --git a/cmd/mstorectl/filecmd.go b/cmd/mstorectl/filecmd.go new file mode 100644 index 0000000..c9a5e2a --- /dev/null +++ b/cmd/mstorectl/filecmd.go @@ -0,0 +1,112 @@ +package main + +import ( + "github.com/spf13/cobra" +) + +func (util *FileUtil) CreateFileCmds() *cobra.Command { + var subCmd = &cobra.Command{ + Use: "file", + Short: "File operation", + } + // PutFile + var putFileCmd = &cobra.Command{ + Use: "put", + Short: "Put file to storage", + Run: util.PutFile, + } + putFileCmd.Flags().StringVarP(&util.putFileParams.Username, "username", "u", "", "Username") + putFileCmd.Flags().StringVarP(&util.putFileParams.Password, "password", "p", "", "Password") + putFileCmd.Flags().StringVarP(&util.putFileParams.Source, "src", "s", "", "Source path") + putFileCmd.Flags().StringVarP(&util.putFileParams.Dest, "dest", "d", "", "Desctination path") + + subCmd.AddCommand(putFileCmd) + + // GetFile + var getFileCmd = &cobra.Command{ + Use: "get", + Short: "Get file from storage", + Run: util.GetFile, + } + getFileCmd.Flags().StringVarP(&util.getFileParams.Username, "username", "u", "", "Username") + getFileCmd.Flags().StringVarP(&util.getFileParams.Password, "password", "p", "", "Password") + getFileCmd.Flags().StringVarP(&util.getFileParams.Source, "src", "s", "", "Source path") + getFileCmd.Flags().StringVarP(&util.getFileParams.Dest, "dest", "d", "", "Desctination path") + + subCmd.AddCommand(getFileCmd) + + // FileExists + var fileExistsCmd = &cobra.Command{ + Use: "exist", + Short: "Check file into storage", + Run: util.FileExists, + } + fileExistsCmd.Flags().StringVarP(&util.fileExistsParams.Username, "username", "u", "", "Username") + fileExistsCmd.Flags().StringVarP(&util.fileExistsParams.Password, "password", "p", "", "Password") + fileExistsCmd.Flags().StringVarP(&util.fileExistsParams.Filepath, "path", "d", "", "File path") + + subCmd.AddCommand(fileExistsCmd) + + // FileExists + var deleteFileCmd = &cobra.Command{ + Use: "delete", + Short: "Delete file in storage", + Run: util.DeleteFile, + } + deleteFileCmd.Flags().StringVarP(&util.deleteFileParams.Username, "username", "u", "", "Username") + deleteFileCmd.Flags().StringVarP(&util.deleteFileParams.Password, "password", "p", "", "Password") + deleteFileCmd.Flags().StringVarP(&util.deleteFileParams.Filepath, "path", "d", "", "File path") + + subCmd.AddCommand(deleteFileCmd) + + return subCmd +} + +type FileUtil struct { + fileExistsParams FileExistsParams + putFileParams PutFileParams + getFileParams GetFileParams + deleteFileParams DeleteFileParams +} + +// File exists +type FileExistsParams struct { + Filepath string + Username string + Password string +} + +func (util *FileUtil) FileExists(cmd *cobra.Command, args []string) { +} + +// Put file +type PutFileParams struct { + Source string + Dest string + Username string + Password string +} + +func (util *FileUtil) PutFile(cmd *cobra.Command, args []string) { +} + +// Get file +type GetFileParams struct { + Source string + Dest string + Username string + Password string +} + +func (util *FileUtil) GetFile(cmd *cobra.Command, args []string) { +} + +// Delete file +type DeleteFileParams struct { + Filepath string + Username string + Password string +} + +func (util *FileUtil) DeleteFile(cmd *cobra.Command, args []string) { +} diff --git a/cmd/mstorectl/imageaux.go b/cmd/mstorectl/imageaux.go new file mode 100644 index 0000000..016c8d0 --- /dev/null +++ b/cmd/mstorectl/imageaux.go @@ -0,0 +1,18 @@ +package main + +import ( + "crypto/tls" + "net/http" +) + +type roundTripper struct{} + +func (t *roundTripper) RoundTrip(r *http.Request) (*http.Response, error) { + tlsConfig := &tls.Config{ + InsecureSkipVerify: true, + } + httpTransport := &http.Transport{ + TLSClientConfig: tlsConfig, + } + return httpTransport.RoundTrip(r) +} diff --git a/cmd/mstorectl/imagecmd.go b/cmd/mstorectl/imagecmd.go new file mode 100644 index 0000000..d8f12ea --- /dev/null +++ b/cmd/mstorectl/imagecmd.go @@ -0,0 +1,115 @@ +package main + +import ( + "github.com/spf13/cobra" +) + +func (util *ImageUtil) CreateImageCmds() *cobra.Command { + const defaultTimeout uint64 = 30 // Second + + var subCmd = &cobra.Command{ + Use: "image", + Short: "Image operation", + } + + // ImageInfo + var imageInfoCmd = &cobra.Command{ + Use: "info", + Short: "Show container image info", + Run: util.ImageInfo, + } + imageInfoCmd.Flags().StringVarP(&util.imageInfoParams.Username, "username", "u", "", "Username") + imageInfoCmd.Flags().StringVarP(&util.imageInfoParams.Password, "password", "p", "", "Password") + imageInfoCmd.Flags().StringVarP(&util.imageInfoParams.Imagepath, "image", "i", "", "Remote image path") + imageInfoCmd.Flags().Uint64VarP(&util.imageInfoParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") + imageInfoCmd.MarkFlagRequired("image") + + subCmd.AddCommand(imageInfoCmd) + + // PullImage + var pullImageCmd = &cobra.Command{ + Use: "pull", + Short: "Pull container image into local file", + Run: util.PullImage, + } + pullImageCmd.Flags().StringVarP(&util.pullImageParams.Username, "username", "u", "", "Username") + pullImageCmd.Flags().StringVarP(&util.pullImageParams.Password, "password", "p", "", "Password") + pullImageCmd.Flags().StringVarP(&util.pullImageParams.Imagepath, "image", "i", "", "Remote image path") + pullImageCmd.Flags().StringVarP(&util.pullImageParams.Filepath, "file", "f", "", "Local file path") + pullImageCmd.Flags().Uint64VarP(&util.pullImageParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") + pullImageCmd.MarkFlagRequired("image") + pullImageCmd.MarkFlagRequired("file") + subCmd.AddCommand(pullImageCmd) + + // PushImage + var pushImageCmd = &cobra.Command{ + Use: "push", + Short: "Pull container image into local file", + Run: util.PushImage, + } + pushImageCmd.Flags().StringVarP(&util.pushImageParams.Username, "username", "u", "", "Username") + pushImageCmd.Flags().StringVarP(&util.pushImageParams.Password, "password", "p", "", "Password") + pushImageCmd.Flags().StringVarP(&util.pushImageParams.Imagepath, "image", "i", "", "Remote image path") + pushImageCmd.Flags().StringVarP(&util.pushImageParams.Filepath, "file", "f", "", "Local file path") + pushImageCmd.Flags().Uint64VarP(&util.pushImageParams.Timeout, "timeout", "t", defaultTimeout, "Operation timeout") + pushImageCmd.MarkFlagRequired("image") + pushImageCmd.MarkFlagRequired("file") + subCmd.AddCommand(pushImageCmd) + + return subCmd +} + +type ImageUtil struct { + imageInfoParams ImageInfoParams + pullImageParams PullImageParams + pushImageParams PushImageParams +} + +// ImageInfo +type ImageInfoParams struct { + Imagepath string + Timeout uint64 + Username string + Password string +} + +type ImageInfoResult struct { + ImageInfo ImageDescr `json:"imageInfo"` +} + +func (util *ImageUtil) ImageInfo(cmd *cobra.Command, args []string) { + res, err := util.imageInfo(&util.imageInfoParams) + printResponse(res, err) +} + +// PullImage +type PullImageParams struct { + Imagepath string + Filepath string + Timeout uint64 + Username string + Password string +} + +type PullImageResult struct{} + +func (util *ImageUtil) PullImage(cmd *cobra.Command, args []string) { + res, err := util.pullImage(&util.pullImageParams) + printResponse(res, err) +} + +// PushImage +type PushImageParams struct { + Imagepath string + Filepath string + Timeout uint64 + Username string + Password string +} + +type PushImageResult struct{} + +func (util *ImageUtil) PushImage(cmd *cobra.Command, args []string) { + res, err := util.pushImage(&util.pushImageParams) + printResponse(res, err) +} diff --git a/cmd/mstorectl/imageinfo.go b/cmd/mstorectl/imageinfo.go new file mode 100644 index 0000000..3e71c75 --- /dev/null +++ b/cmd/mstorectl/imageinfo.go @@ -0,0 +1,114 @@ +package main + +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 (util *ImageUtil) imageInfo(params *ImageInfoParams) (*ImageInfoResult, error) { + var err error + res := &ImageInfoResult{} + + 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 + + return res, err +} diff --git a/cmd/mstorectl/imagepull.go b/cmd/mstorectl/imagepull.go new file mode 100644 index 0000000..9f71274 --- /dev/null +++ b/cmd/mstorectl/imagepull.go @@ -0,0 +1,76 @@ +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" +) + +func (util *ImageUtil) pullImage(params *PullImageParams) (*PullImageResult, error) { + var err error + + ctx, _ := context.WithTimeout(context.Background(), time.Duration(params.Timeout)*time.Second) + + 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)} + + 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 new file mode 100644 index 0000000..9aec838 --- /dev/null +++ b/cmd/mstorectl/imagepush.go @@ -0,0 +1,106 @@ +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" +) + +func (util *ImageUtil) pushImage(params *PushImageParams) (*PushImageResult, error) { + var err error + ctx, _ := context.WithTimeout(context.Background(), time.Duration(params.Timeout)*time.Second) + 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{} + + 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/cmd/mstorectl/main.go b/cmd/mstorectl/main.go index c3a65b2..bab6457 100644 --- a/cmd/mstorectl/main.go +++ b/cmd/mstorectl/main.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "path/filepath" "github.com/spf13/cobra" "sigs.k8s.io/yaml" @@ -33,9 +34,11 @@ func NewUtil() *Util { func (util *Util) Build() error { var err error + execName := filepath.Base(os.Args[0]) rootCmd := cobra.Command{ - Use: "cmd", - Short: "A brief description the command", + Use: execName, + Short: "\nA brief description the command", + SilenceUsage: true, } rootCmd.CompletionOptions.DisableDefaultCmd = true rootCmd.AddCommand(util.CreateFileCmds()) diff --git a/cmd/mstorectl/taraux.go b/cmd/mstorectl/taraux.go new file mode 100644 index 0000000..1e9b177 --- /dev/null +++ b/cmd/mstorectl/taraux.go @@ -0,0 +1,129 @@ +package main + +import ( + "archive/tar" + "encoding/hex" + "fmt" + "io" + "math/rand" + "os" + "path/filepath" + "strings" +) + +func archiveDir(srcDir, dstPath string) error { + var err error + srcDir = filepath.Clean(srcDir) + dstPath = filepath.Clean(dstPath) + + err = os.MkdirAll(filepath.Dir(dstPath), 0755) + if err != nil { + return err + } + tarFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) + if err != nil { + return err + } + defer tarFile.Close() + + tarWriter := tar.NewWriter(tarFile) + defer tarWriter.Close() + + walker := func(filePath string, fileInfo os.FileInfo, err error) error { + if err != nil { + return err + } + if !fileInfo.Mode().IsRegular() { + return nil + } + header, err := tar.FileInfoHeader(fileInfo, fileInfo.Name()) + if err != nil { + return err + } + header.Name = strings.TrimPrefix(filePath, filepath.Clean(srcDir)) + header.Name = strings.TrimPrefix(header.Name, string(filepath.Separator)) + + err = tarWriter.WriteHeader(header) + if err != nil { + return err + } + file, err := os.Open(filePath) + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(tarWriter, file) + if err != nil { + return err + } + return nil + } + err = filepath.Walk(srcDir, walker) + if err != nil { + return err + } + return err +} + +func unarchive(filePath, dstDir string) error { + var err error + err = os.MkdirAll(dstDir, 0755) + if err != nil { + return err + } + file, err := os.OpenFile(filePath, os.O_RDONLY, 0) + if err != nil { + return err + } + defer file.Close() + + tarReader := tar.NewReader(file) + //defer tarReader.Close() + for { + header, err := tarReader.Next() + switch { + case err == io.EOF: + return nil + case err != nil: + return err + case header == nil: + continue + } + target := filepath.Join(dstDir, header.Name) + target = filepath.Clean(target) + //fileInfo := header.FileInfo() + switch header.Typeflag { + case tar.TypeDir: + _, err := os.Stat(target) + if err != nil { + err := os.MkdirAll(target, 0755) + if err != nil { + return err + } + + } + case tar.TypeReg: + err := os.MkdirAll(filepath.Dir(target), 0755) + if err != nil { + return err + } + file, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(header.Mode)) + if err != nil { + return err + } + _, err = io.Copy(file, tarReader) + if err != nil { + return err + } + file.Close() + } + } + 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) +} diff --git a/cmd/mstored/main.go b/cmd/mstored/main.go new file mode 100644 index 0000000..e24e407 --- /dev/null +++ b/cmd/mstored/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "os" + + "mstore/app/logger" + "mstore/app/server" +) + +func run() error { + var err error + srv, err := server.NewServer() + if err != nil { + return err + } + err = srv.Configure() + if err != nil { + return err + } + err = srv.Daemonize() + if err != nil { + return err + } + err = srv.Build() + if err != nil { + return err + } + err = srv.Run() + if err != nil { + return err + } + return err +} + +func main() { + log := logger.NewLogger("main") + err := run() + if err != nil { + log.Errorf("%v", err) + os.Exit(1) + } + os.Exit(0) +}