From b07417f738a997683bad6338beafc748d43577e9 Mon Sep 17 00:00:00 2001 From: Laitron Date: Fri, 6 Jan 2023 21:21:54 +0800 Subject: [PATCH] [Refactor] Refactor the compose command flagging process Signed-off-by: Laitron --- cmd/nerdctl/compose.go | 134 ++------------------------------- cmd/nerdctl/compose_build.go | 8 +- cmd/nerdctl/compose_config.go | 9 ++- cmd/nerdctl/compose_create.go | 8 +- cmd/nerdctl/compose_down.go | 9 ++- cmd/nerdctl/compose_exec.go | 8 +- cmd/nerdctl/compose_images.go | 7 +- cmd/nerdctl/compose_kill.go | 9 ++- cmd/nerdctl/compose_logs.go | 10 ++- cmd/nerdctl/compose_pause.go | 16 +++- cmd/nerdctl/compose_port.go | 9 ++- cmd/nerdctl/compose_ps.go | 9 ++- cmd/nerdctl/compose_pull.go | 10 ++- cmd/nerdctl/compose_push.go | 10 ++- cmd/nerdctl/compose_restart.go | 9 ++- cmd/nerdctl/compose_rm.go | 8 +- cmd/nerdctl/compose_run.go | 9 ++- cmd/nerdctl/compose_start.go | 9 ++- cmd/nerdctl/compose_stop.go | 9 ++- cmd/nerdctl/compose_top.go | 9 ++- cmd/nerdctl/compose_up.go | 9 ++- pkg/cmd/compose/compose.go | 134 +++++++++++++++++++++++++++++++++ pkg/composer/composer.go | 1 - 23 files changed, 286 insertions(+), 167 deletions(-) create mode 100644 pkg/cmd/compose/compose.go diff --git a/cmd/nerdctl/compose.go b/cmd/nerdctl/compose.go index 3a5fbed9d50..7b2ffb6a84b 100644 --- a/cmd/nerdctl/compose.go +++ b/cmd/nerdctl/compose.go @@ -17,24 +17,7 @@ package main import ( - "context" - "errors" - "fmt" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/errdefs" - "github.com/containerd/containerd/platforms" - "github.com/containerd/nerdctl/pkg/api/types" "github.com/containerd/nerdctl/pkg/composer" - "github.com/containerd/nerdctl/pkg/composer/serviceparser" - "github.com/containerd/nerdctl/pkg/cosignutil" - "github.com/containerd/nerdctl/pkg/imgutil" - "github.com/containerd/nerdctl/pkg/ipfs" - "github.com/containerd/nerdctl/pkg/netutil" - "github.com/containerd/nerdctl/pkg/referenceutil" - ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" ) @@ -81,33 +64,26 @@ func newComposeCommand() *cobra.Command { return composeCommand } -func getComposer(cmd *cobra.Command, client *containerd.Client, globalOptions *types.GlobalCommandOptions) (*composer.Composer, error) { +func getComposeOptions(cmd *cobra.Command, debugFull, experimental bool) (composer.Options, error) { nerdctlCmd, nerdctlArgs := globalFlags(cmd) projectDirectory, err := cmd.Flags().GetString("project-directory") if err != nil { - return nil, err + return composer.Options{}, err } envFile, err := cmd.Flags().GetString("env-file") if err != nil { - return nil, err + return composer.Options{}, err } projectName, err := cmd.Flags().GetString("project-name") if err != nil { - return nil, err + return composer.Options{}, err } - debugFull := globalOptions.DebugFull - snapshotter := globalOptions.Snapshotter files, err := cmd.Flags().GetStringArray("file") if err != nil { - return nil, err + return composer.Options{}, err } - insecure := globalOptions.InsecureRegistry - cniPath := globalOptions.CNIPath - cniNetconfpath := globalOptions.CNINetConfPath - hostsDirs := globalOptions.HostsDir - experimental := globalOptions.Experimental - o := composer.Options{ + return composer.Options{ Project: projectName, ProjectDirectory: projectDirectory, ConfigPaths: files, @@ -116,101 +92,5 @@ func getComposer(cmd *cobra.Command, client *containerd.Client, globalOptions *t NerdctlArgs: nerdctlArgs, DebugPrintFull: debugFull, Experimental: experimental, - } - - cniEnv, err := netutil.NewCNIEnv(cniPath, cniNetconfpath, netutil.WithDefaultNetwork()) - if err != nil { - return nil, err - } - networkConfigs, err := cniEnv.NetworkList() - if err != nil { - return nil, err - } - - o.NetworkExists = func(netName string) (bool, error) { - for _, f := range networkConfigs { - if f.Name == netName { - return true, nil - } - } - return false, nil - } - - volStore, err := getVolumeStore(globalOptions) - if err != nil { - return nil, err - } - - o.VolumeExists = func(volName string) (bool, error) { - if _, volGetErr := volStore.Get(volName, false); volGetErr == nil { - return true, nil - } else if errors.Is(volGetErr, errdefs.ErrNotFound) { - return false, nil - } else { - return false, volGetErr - } - } - - o.ImageExists = func(ctx context.Context, rawRef string) (bool, error) { - refNamed, err := referenceutil.ParseAny(rawRef) - if err != nil { - return false, err - } - ref := refNamed.String() - if _, err := client.ImageService().Get(ctx, ref); err != nil { - if errors.Is(err, errdefs.ErrNotFound) { - return false, nil - } - return false, err - } - return true, nil - } - - o.EnsureImage = func(ctx context.Context, imageName, pullMode, platform string, ps *serviceparser.Service, quiet bool) error { - ocispecPlatforms := []ocispec.Platform{platforms.DefaultSpec()} - if platform != "" { - parsed, err := platforms.Parse(platform) - if err != nil { - return err - } - ocispecPlatforms = []ocispec.Platform{parsed} // no append - } - - // IPFS reference - if scheme, ref, err := referenceutil.ParseIPFSRefWithScheme(imageName); err == nil { - _, err = ipfs.EnsureImage(ctx, client, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, scheme, ref, - pullMode, ocispecPlatforms, nil, quiet) - return err - } - - ref := imageName - if verifier, ok := ps.Unparsed.Extensions[serviceparser.ComposeVerify]; ok { - switch verifier { - case "cosign": - if !o.Experimental { - return fmt.Errorf("cosign only work with enable experimental feature") - } - - // if key is given, use key mode, otherwise use keyless mode. - keyRef := "" - if keyVal, ok := ps.Unparsed.Extensions[serviceparser.ComposeCosignPublicKey]; ok { - keyRef = keyVal.(string) - } - - ref, err = cosignutil.VerifyCosign(ctx, ref, keyRef, hostsDirs) - if err != nil { - return err - } - case "none": - logrus.Debugf("verification process skipped") - default: - return fmt.Errorf("no verifier found: %s", verifier) - } - } - _, err = imgutil.EnsureImage(ctx, client, cmd.OutOrStdout(), cmd.ErrOrStderr(), snapshotter, ref, - pullMode, insecure, hostsDirs, ocispecPlatforms, nil, quiet) - return err - } - - return composer.New(o, client) + }, nil } diff --git a/cmd/nerdctl/compose_build.go b/cmd/nerdctl/compose_build.go index 85184445767..be59dbad7b7 100644 --- a/cmd/nerdctl/compose_build.go +++ b/cmd/nerdctl/compose_build.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -60,8 +61,11 @@ func composeBuildAction(cmd *cobra.Command, args []string) error { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_config.go b/cmd/nerdctl/compose_config.go index 4c4d7e17689..90c506ce092 100644 --- a/cmd/nerdctl/compose_config.go +++ b/cmd/nerdctl/compose_config.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -73,11 +74,15 @@ func composeConfigAction(cmd *cobra.Command, args []string) error { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) if err != nil { return err } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) + if err != nil { + return err + } + if quiet { return nil } diff --git a/cmd/nerdctl/compose_create.go b/cmd/nerdctl/compose_create.go index d03b44e0d3a..7b60ed8dc98 100644 --- a/cmd/nerdctl/compose_create.go +++ b/cmd/nerdctl/compose_create.go @@ -20,6 +20,7 @@ import ( "errors" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -73,8 +74,11 @@ func composeCreateAction(cmd *cobra.Command, args []string) error { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_down.go b/cmd/nerdctl/compose_down.go index 8d3f1a587a7..236f96fd61a 100644 --- a/cmd/nerdctl/compose_down.go +++ b/cmd/nerdctl/compose_down.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -55,11 +56,15 @@ func composeDownAction(cmd *cobra.Command, args []string) error { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) if err != nil { return err } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) + if err != nil { + return err + } + downOpts := composer.DownOptions{ RemoveVolumes: volumes, RemoveOrphans: removeOrphans, diff --git a/cmd/nerdctl/compose_exec.go b/cmd/nerdctl/compose_exec.go index 7f92e6db919..06919b6309e 100644 --- a/cmd/nerdctl/compose_exec.go +++ b/cmd/nerdctl/compose_exec.go @@ -20,6 +20,7 @@ import ( "errors" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -104,8 +105,11 @@ func composeExecAction(cmd *cobra.Command, args []string) error { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_images.go b/cmd/nerdctl/compose_images.go index 136897686fd..d4bc71233de 100644 --- a/cmd/nerdctl/compose_images.go +++ b/cmd/nerdctl/compose_images.go @@ -26,6 +26,7 @@ import ( "github.com/containerd/containerd/pkg/progress" "github.com/containerd/containerd/snapshots" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/imgutil" "github.com/containerd/nerdctl/pkg/labels" "github.com/containerd/nerdctl/pkg/strutil" @@ -62,7 +63,11 @@ func composeImagesAction(cmd *cobra.Command, args []string) error { } defer cancel() - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_kill.go b/cmd/nerdctl/compose_kill.go index 8153aeb48e4..1e483273ff1 100644 --- a/cmd/nerdctl/compose_kill.go +++ b/cmd/nerdctl/compose_kill.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -43,15 +44,21 @@ func composeKillAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) if err != nil { return err } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) + if err != nil { + return err + } + killOpts := composer.KillOptions{ Signal: signal, } diff --git a/cmd/nerdctl/compose_logs.go b/cmd/nerdctl/compose_logs.go index a5cd5a18df4..79902f7bad2 100644 --- a/cmd/nerdctl/compose_logs.go +++ b/cmd/nerdctl/compose_logs.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -63,16 +64,21 @@ func composeLogsAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } + lo := composer.LogsOptions{ Follow: follow, Timestamps: timestamps, diff --git a/cmd/nerdctl/compose_pause.go b/cmd/nerdctl/compose_pause.go index 9ad0fb6292f..9374a797219 100644 --- a/cmd/nerdctl/compose_pause.go +++ b/cmd/nerdctl/compose_pause.go @@ -22,6 +22,7 @@ import ( "github.com/containerd/containerd" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/labels" "github.com/spf13/cobra" "golang.org/x/sync/errgroup" @@ -44,16 +45,21 @@ func composePauseAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } + serviceNames, err := c.ServiceNames(args...) if err != nil { return err @@ -112,7 +118,11 @@ func composeUnpauseAction(cmd *cobra.Command, args []string) error { } defer cancel() - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_port.go b/cmd/nerdctl/compose_port.go index 0efa45ed58a..92c3ea3189a 100644 --- a/cmd/nerdctl/compose_port.go +++ b/cmd/nerdctl/compose_port.go @@ -21,6 +21,7 @@ import ( "strconv" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -70,13 +71,17 @@ func composePortAction(cmd *cobra.Command, args []string) error { if port <= 0 { return fmt.Errorf("unexpected port: %d", port) } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_ps.go b/cmd/nerdctl/compose_ps.go index 521aa6b6351..baaa9a35357 100644 --- a/cmd/nerdctl/compose_ps.go +++ b/cmd/nerdctl/compose_ps.go @@ -24,6 +24,7 @@ import ( "github.com/containerd/containerd" gocni "github.com/containerd/go-cni" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/containerutil" "github.com/containerd/nerdctl/pkg/formatter" "github.com/containerd/nerdctl/pkg/labels" @@ -72,13 +73,17 @@ func composePsAction(cmd *cobra.Command, args []string) error { if format != "json" && format != "" { return fmt.Errorf("unsupported format %s, supported formats are: [json]", format) } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_pull.go b/cmd/nerdctl/compose_pull.go index 479aaeb1445..9d004353fc5 100644 --- a/cmd/nerdctl/compose_pull.go +++ b/cmd/nerdctl/compose_pull.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -39,16 +40,21 @@ func composePullAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } + quiet, err := cmd.Flags().GetBool("quiet") if err != nil { return err diff --git a/cmd/nerdctl/compose_push.go b/cmd/nerdctl/compose_push.go index 06def7aa175..2c899dabf39 100644 --- a/cmd/nerdctl/compose_push.go +++ b/cmd/nerdctl/compose_push.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -38,16 +39,21 @@ func composePushAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } + po := composer.PushOptions{} return c.Push(ctx, po, args) } diff --git a/cmd/nerdctl/compose_restart.go b/cmd/nerdctl/compose_restart.go index e3f8b1012fe..adb47e3dee4 100644 --- a/cmd/nerdctl/compose_restart.go +++ b/cmd/nerdctl/compose_restart.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -48,13 +49,17 @@ func composeRestartAction(cmd *cobra.Command, args []string) error { } opt.Timeout = &timeValue } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_rm.go b/cmd/nerdctl/compose_rm.go index 6aefa0db0c1..6ac686f6b86 100644 --- a/cmd/nerdctl/compose_rm.go +++ b/cmd/nerdctl/compose_rm.go @@ -21,6 +21,7 @@ import ( "strings" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -72,12 +73,17 @@ func composeRemoveAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_run.go b/cmd/nerdctl/compose_run.go index d654f3b7774..c92c5ab1ae9 100644 --- a/cmd/nerdctl/compose_run.go +++ b/cmd/nerdctl/compose_run.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -167,13 +168,17 @@ func composeRunAction(cmd *cobra.Command, args []string) error { if tty && detach { return errors.New("currently flag -t and -d cannot be specified together (FIXME)") } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_start.go b/cmd/nerdctl/compose_start.go index 8ef82b53839..07cf092d521 100644 --- a/cmd/nerdctl/compose_start.go +++ b/cmd/nerdctl/compose_start.go @@ -24,6 +24,7 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/errdefs" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/containerutil" "github.com/containerd/nerdctl/pkg/labels" "github.com/spf13/cobra" @@ -47,13 +48,17 @@ func composeStartAction(cmd *cobra.Command, args []string) error { if err != nil { return err } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_stop.go b/cmd/nerdctl/compose_stop.go index e85b8b68748..b35d4911143 100644 --- a/cmd/nerdctl/compose_stop.go +++ b/cmd/nerdctl/compose_stop.go @@ -18,6 +18,7 @@ package main import ( "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -48,13 +49,17 @@ func composeStopAction(cmd *cobra.Command, args []string) error { } opt.Timeout = &timeValue } + client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), globalOptions.Namespace, globalOptions.Address) if err != nil { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } diff --git a/cmd/nerdctl/compose_top.go b/cmd/nerdctl/compose_top.go index 11a2c6b8a53..01167391579 100644 --- a/cmd/nerdctl/compose_top.go +++ b/cmd/nerdctl/compose_top.go @@ -21,6 +21,7 @@ import ( "github.com/containerd/containerd" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/containerutil" "github.com/containerd/nerdctl/pkg/labels" "github.com/spf13/cobra" @@ -49,8 +50,11 @@ func composeTopAction(cmd *cobra.Command, args []string) error { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) + if err != nil { + return err + } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) if err != nil { return err } @@ -62,7 +66,6 @@ func composeTopAction(cmd *cobra.Command, args []string) error { if err != nil { return err } - stdout := cmd.OutOrStdout() for _, c := range containers { cStatus, err := containerutil.ContainerStatus(ctx, c) diff --git a/cmd/nerdctl/compose_up.go b/cmd/nerdctl/compose_up.go index c44cdb6d2f5..f1c3e05535d 100644 --- a/cmd/nerdctl/compose_up.go +++ b/cmd/nerdctl/compose_up.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/containerd/nerdctl/pkg/clientutil" + "github.com/containerd/nerdctl/pkg/cmd/compose" "github.com/containerd/nerdctl/pkg/composer" "github.com/spf13/cobra" ) @@ -109,11 +110,15 @@ func composeUpAction(cmd *cobra.Command, services []string) error { return err } defer cancel() - - c, err := getComposer(cmd, client, globalOptions) + options, err := getComposeOptions(cmd, globalOptions.DebugFull, globalOptions.Experimental) if err != nil { return err } + c, err := compose.New(client, globalOptions, options, cmd.OutOrStdout(), cmd.ErrOrStderr()) + if err != nil { + return err + } + uo := composer.UpOptions{ Detach: detach, NoBuild: noBuild, diff --git a/pkg/cmd/compose/compose.go b/pkg/cmd/compose/compose.go new file mode 100644 index 00000000000..3efcf1fdaf4 --- /dev/null +++ b/pkg/cmd/compose/compose.go @@ -0,0 +1,134 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package compose + +import ( + "context" + "errors" + "fmt" + "io" + + "github.com/containerd/containerd" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/platforms" + "github.com/containerd/nerdctl/pkg/api/types" + "github.com/containerd/nerdctl/pkg/cmd/volume" + "github.com/containerd/nerdctl/pkg/composer" + "github.com/containerd/nerdctl/pkg/composer/serviceparser" + "github.com/containerd/nerdctl/pkg/cosignutil" + "github.com/containerd/nerdctl/pkg/imgutil" + "github.com/containerd/nerdctl/pkg/ipfs" + "github.com/containerd/nerdctl/pkg/netutil" + "github.com/containerd/nerdctl/pkg/referenceutil" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/sirupsen/logrus" +) + +func New(client *containerd.Client, globalOptions *types.GlobalCommandOptions, options composer.Options, stdout, stderr io.Writer) (*composer.Composer, error) { + cniEnv, err := netutil.NewCNIEnv(globalOptions.CNIPath, globalOptions.CNINetConfPath, netutil.WithDefaultNetwork()) + if err != nil { + return nil, err + } + networkConfigs, err := cniEnv.NetworkList() + if err != nil { + return nil, err + } + options.NetworkExists = func(netName string) (bool, error) { + for _, f := range networkConfigs { + if f.Name == netName { + return true, nil + } + } + return false, nil + } + + volStore, err := volume.Store(globalOptions.Namespace, globalOptions.DataRoot, globalOptions.Address) + if err != nil { + return nil, err + } + options.VolumeExists = func(volName string) (bool, error) { + if _, volGetErr := volStore.Get(volName, false); volGetErr == nil { + return true, nil + } else if errors.Is(volGetErr, errdefs.ErrNotFound) { + return false, nil + } else { + return false, volGetErr + } + } + + options.ImageExists = func(ctx context.Context, rawRef string) (bool, error) { + refNamed, err := referenceutil.ParseAny(rawRef) + if err != nil { + return false, err + } + ref := refNamed.String() + if _, err := client.ImageService().Get(ctx, ref); err != nil { + if errors.Is(err, errdefs.ErrNotFound) { + return false, nil + } + return false, err + } + return true, nil + } + + options.EnsureImage = func(ctx context.Context, imageName, pullMode, platform string, ps *serviceparser.Service, quiet bool) error { + ocispecPlatforms := []ocispec.Platform{platforms.DefaultSpec()} + if platform != "" { + parsed, err := platforms.Parse(platform) + if err != nil { + return err + } + ocispecPlatforms = []ocispec.Platform{parsed} // no append + } + + // IPFS reference + if scheme, ref, err := referenceutil.ParseIPFSRefWithScheme(imageName); err == nil { + _, err = ipfs.EnsureImage(ctx, client, stdout, stderr, globalOptions.Snapshotter, scheme, ref, + pullMode, ocispecPlatforms, nil, quiet) + return err + } + + ref := imageName + if verifier, ok := ps.Unparsed.Extensions[serviceparser.ComposeVerify]; ok { + switch verifier { + case "cosign": + if !options.Experimental { + return fmt.Errorf("cosign only work with enable experimental feature") + } + + // if key is given, use key mode, otherwise use keyless mode. + keyRef := "" + if keyVal, ok := ps.Unparsed.Extensions[serviceparser.ComposeCosignPublicKey]; ok { + keyRef = keyVal.(string) + } + ref, err = cosignutil.VerifyCosign(ctx, ref, keyRef, globalOptions.HostsDir) + if err != nil { + return err + } + case "none": + logrus.Debugf("verification process skipped") + default: + return fmt.Errorf("no verifier found: %s", verifier) + } + } + _, err := imgutil.EnsureImage(ctx, client, stdout, stderr, globalOptions.Snapshotter, ref, + pullMode, globalOptions.InsecureRegistry, globalOptions.HostsDir, ocispecPlatforms, nil, quiet) + return err + } + + return composer.New(options, client) +} diff --git a/pkg/composer/composer.go b/pkg/composer/composer.go index bce313bd252..d848280ca7f 100644 --- a/pkg/composer/composer.go +++ b/pkg/composer/composer.go @@ -29,7 +29,6 @@ import ( "github.com/containerd/containerd/identifiers" "github.com/containerd/nerdctl/pkg/composer/serviceparser" "github.com/containerd/nerdctl/pkg/reflectutil" - "github.com/sirupsen/logrus" )