From dd3c0cdf1c07cb781dd8542eb3d77e591d081629 Mon Sep 17 00:00:00 2001 From: Christophe VILA Date: Mon, 25 Jan 2021 22:18:19 +0100 Subject: [PATCH] Added pull command --- cmd/list.go | 3 +- cmd/pull.go | 109 ++++++++++++++++++++++++++++++ cmd/root.go | 1 + cmd/save.go | 7 +- internal/containerd/containerd.go | 8 ++- internal/docker/docker.go | 23 +++++++ plugin.yaml | 2 +- 7 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 cmd/pull.go create mode 100644 internal/docker/docker.go diff --git a/cmd/list.go b/cmd/list.go index b104596..6a7f8d4 100644 --- a/cmd/list.go +++ b/cmd/list.go @@ -14,6 +14,7 @@ import ( "log" "os" "path/filepath" + "runtime" "strings" "sync" "time" @@ -267,7 +268,7 @@ func (l *listCmd) list() ([]string, error) { var wg sync.WaitGroup tasks := make(chan processChartInfo) taskErrors := newTaskErrors() - for i := 0; i < 4; i++ { + for i := 0; i < runtime.NumCPU(); i++ { wg.Add(1) go func(tasks chan processChartInfo, wg *sync.WaitGroup) { defer wg.Done() diff --git a/cmd/pull.go b/cmd/pull.go new file mode 100644 index 0000000..1e43374 --- /dev/null +++ b/cmd/pull.go @@ -0,0 +1,109 @@ +package cmd + +import ( + "github.com/gemalto/helm-image/internal/docker" + "github.com/spf13/cobra" + cliValues "helm.sh/helm/v3/pkg/cli/values" + "io" + "os" + "strings" +) + +type pullCmd struct { + chartName string + namespace string + excludes []string + auths []string + valuesOpts cliValues.Options + helmPath string + verbose bool + debug bool +} + +func newPullCmd(out io.Writer) *cobra.Command { + p := &pullCmd{} + + cmd := &cobra.Command{ + Use: "pull", + Short: "pull docker images referenced in a chart", + Long: "pull docker images referenced in a chart", + Args: cobra.MinimumNArgs(1), + SilenceUsage: true, + RunE: func(cmd *cobra.Command, args []string) error { + p.chartName = args[0] + return p.pull() + }, + } + + flags := cmd.Flags() + + flags.StringSliceVarP(&p.auths, "auth", "a", []string{}, "specify private registries which need authentication during pull") + flags.StringSliceVarP(&p.excludes, "exclude", "x", []string{}, "specify docker images to be excluded from pulls") + flags.StringSliceVarP(&p.valuesOpts.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)") + flags.StringArrayVar(&p.valuesOpts.Values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") + flags.StringArrayVar(&p.valuesOpts.StringValues, "set-string", []string{}, "set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)") + flags.StringArrayVar(&p.valuesOpts.FileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") + flags.BoolVarP(&p.verbose, "verbose", "v", false, "enable verbose output") + + // When called through helm, helm path is transmitted through the HELM_BIN envvar + p.helmPath = os.Getenv("HELM_BIN") + + // When called through helm, debug mode is transmitted through the HELM_DEBUG envvar + helmDebug := os.Getenv("HELM_DEBUG") + if helmDebug == "1" || strings.EqualFold(helmDebug, "true") || strings.EqualFold(helmDebug, "on") { + p.debug = true + } + + // When called through helm, namespace is transmitted through the HELM_NAMESPACE envvar + namespace := os.Getenv("HELM_NAMESPACE") + if len(namespace) > 0 { + p.namespace = namespace + } else { + p.namespace = "default" + } + + return cmd +} + +func (p *pullCmd) pull() error { + l := &listCmd{ + chartName: p.chartName, + namespace: p.namespace, + valuesOpts: p.valuesOpts, + helmPath: p.helmPath, + debug: p.debug, + } + images, err := l.list() + includedImagesMap := map[string]struct{}{} + for _, image := range images { + includedImagesMap[image] = struct{}{} + for _, excludedImage := range p.excludes { + if image == excludedImage { + delete(includedImagesMap, image) + } + } + } + var includedImages []string + for image := range includedImagesMap { + includedImages = append(includedImages, image) + } + if err != nil { + return err + } + //client, err := containerd.ClientWithAddress(os.Getenv("DOCKER_HOST"), l.debug) + //if err != nil { + // return err + //} + //ctx := namespaces.WithNamespace(context.Background(), "default") + //for _, auth := range p.auths { + // registry.AddAuthRegistry(auth) + //} + for _, image := range includedImages { + err = docker.Pull(image, l.debug) + //err = containerd.PullImage(ctx, client, registry.ConsoleCredentials, image, l.debug) + if err != nil { + return err + } + } + return nil +} diff --git a/cmd/root.go b/cmd/root.go index abbbe38..b1d9178 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,6 +14,7 @@ func NewRootCmd(out io.Writer, args []string) *cobra.Command { cmd.AddCommand( newListCmd(out), newSaveCmd(out), + newPullCmd(out), newCacheCmd(out), ) return cmd diff --git a/cmd/save.go b/cmd/save.go index 479721b..9491a65 100644 --- a/cmd/save.go +++ b/cmd/save.go @@ -23,8 +23,9 @@ type saveCmd struct { excludes []string auths []string valuesOpts cliValues.Options - debug bool + helmPath string verbose bool + debug bool } func newSaveCmd(out io.Writer) *cobra.Command { @@ -52,6 +53,9 @@ func newSaveCmd(out io.Writer) *cobra.Command { flags.StringArrayVar(&s.valuesOpts.FileValues, "set-file", []string{}, "set values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2)") flags.BoolVarP(&s.verbose, "verbose", "v", false, "enable verbose output") + // When called through helm, helm path is transmitted through the HELM_BIN envvar + s.helmPath = os.Getenv("HELM_BIN") + // When called through helm, debug mode is transmitted through the HELM_DEBUG envvar helmDebug := os.Getenv("HELM_DEBUG") if helmDebug == "1" || strings.EqualFold(helmDebug, "true") || strings.EqualFold(helmDebug, "on") { @@ -74,6 +78,7 @@ func (s *saveCmd) save() error { chartName: s.chartName, namespace: s.namespace, valuesOpts: s.valuesOpts, + helmPath: s.helmPath, debug: s.debug, } images, err := l.list() diff --git a/internal/containerd/containerd.go b/internal/containerd/containerd.go index 1d6aff5..610c717 100644 --- a/internal/containerd/containerd.go +++ b/internal/containerd/containerd.go @@ -507,7 +507,7 @@ func ListImages(ctx context.Context, client *containerd.Client) error { return nil } -func Client(debug bool) (*containerd.Client, error) { +func ClientWithAddress(address string, debug bool) (*containerd.Client, error) { homeDir, err := os.UserHomeDir() if err != nil { return nil, err @@ -524,7 +524,7 @@ func Client(debug bool) (*containerd.Client, error) { var client *containerd.Client defer closeClient(client) for i := 0; i < 12; i++ { - client, err = containerd.New("\\\\.\\pipe\\containerd-containerd", containerd.WithTimeout(1*time.Second)) + client, err = containerd.New(address, containerd.WithTimeout(1*time.Second)) if client != nil { break } else if err != nil && i > 0 && debug { @@ -537,6 +537,10 @@ func Client(debug bool) (*containerd.Client, error) { return client, nil } +func Client(debug bool) (*containerd.Client, error) { + return ClientWithAddress("\\\\.\\pipe\\containerd-containerd", debug) +} + func Server(serverStarted chan bool, serverKill chan bool, serverKilled chan bool, debug bool) { err := CreateContainerdDirectories() if err != nil { diff --git a/internal/docker/docker.go b/internal/docker/docker.go new file mode 100644 index 0000000..19835cc --- /dev/null +++ b/internal/docker/docker.go @@ -0,0 +1,23 @@ +package docker + +import ( + "log" + "os" + "os/exec" +) + +func Pull(image string, debug bool) error { + dockerPath := "docker" + var myargs = []string{"pull", image} + if debug { + log.Printf("Running %s %v\n", dockerPath, myargs) + } + cmd := exec.Command(dockerPath, myargs...) + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + err := cmd.Run() + if err != nil { + return err + } + return nil +} diff --git a/plugin.yaml b/plugin.yaml index 2ab8db0..6a608e7 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,5 +1,5 @@ name: "image" -version: 1.0.2 +version: 1.0.3 usage: "get docker images from a chart" description: "Helm plugin for getting docker images from a chart" command: "$HELM_PLUGIN_DIR/bin/helm-image"