Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3432: Support --pull flag in nerdctl compose up #3745

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cmd/nerdctl/compose/compose_up.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func newComposeUpCommand() *cobra.Command {
composeUpCommand.Flags().Bool("force-recreate", false, "Recreate containers even if their configuration and image haven't changed.")
composeUpCommand.Flags().Bool("no-recreate", false, "Don't recreate containers if they exist, conflict with --force-recreate.")
composeUpCommand.Flags().StringArray("scale", []string{}, "Scale SERVICE to NUM instances. Overrides the `scale` setting in the Compose file if present.")
composeUpCommand.Flags().String("pull", "", "Pull image before running (\"always\"|\"missing\"|\"never\")")
return composeUpCommand
}

Expand Down Expand Up @@ -96,6 +97,10 @@ func composeUpAction(cmd *cobra.Command, services []string) error {
if err != nil {
return err
}
pull, err := cmd.Flags().GetString("pull")
if err != nil {
return err
}
removeOrphans, err := cmd.Flags().GetBool("remove-orphans")
if err != nil {
return err
Expand Down Expand Up @@ -154,6 +159,7 @@ func composeUpAction(cmd *cobra.Command, services []string) error {
QuietPull: quietPull,
RemoveOrphans: removeOrphans,
Scale: scale,
Pull: pull,
ForceRecreate: forceRecreate,
NoRecreate: noRecreate,
}
Expand Down
54 changes: 54 additions & 0 deletions cmd/nerdctl/compose/compose_up_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,3 +579,57 @@ services:
}
c.Assert(expected)
}

func TestComposeUpPull(t *testing.T) {
base := testutil.NewBase(t)

var dockerComposeYAML = fmt.Sprintf(`
services:
test:
image: %s
command: sh -euxc "echo hi"
`, testutil.CommonImage)

comp := testutil.NewComposeDir(t, dockerComposeYAML)
defer comp.CleanUp()

// Cases where pull is required
for _, pull := range []string{"missing", "always"} {
t.Run(fmt.Sprintf("pull=%s", pull), func(t *testing.T) {
base.Cmd("rmi", "-f", testutil.CommonImage).Run()
base.Cmd("images").AssertOutNotContains(testutil.CommonImage)
t.Cleanup(func() {
base.ComposeCmd("-f", comp.YAMLFullPath(), "down").AssertOK()
})
base.ComposeCmd("-f", comp.YAMLFullPath(), "up", "--pull", pull).AssertOutContains("hi")
})
}

t.Run("pull=never, no pull", func(t *testing.T) {
base.Cmd("rmi", "-f", testutil.CommonImage).Run()
base.Cmd("images").AssertOutNotContains(testutil.CommonImage)
t.Cleanup(func() {
base.ComposeCmd("-f", comp.YAMLFullPath(), "down").AssertOK()
})
base.ComposeCmd("-f", comp.YAMLFullPath(), "up", "--pull", "never").AssertExitCode(1)
})
}

func TestComposeUpServicePullPolicy(t *testing.T) {
base := testutil.NewBase(t)

var dockerComposeYAML = fmt.Sprintf(`
services:
test:
image: %s
command: sh -euxc "echo hi"
pull_policy: "never"
`, testutil.CommonImage)

comp := testutil.NewComposeDir(t, dockerComposeYAML)
defer comp.CleanUp()

base.Cmd("rmi", "-f", testutil.CommonImage).Run()
base.Cmd("images").AssertOutNotContains(testutil.CommonImage)
base.ComposeCmd("-f", comp.YAMLFullPath(), "up").AssertExitCode(1)
}
1 change: 1 addition & 0 deletions docs/command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,7 @@ Flags:
- :whale: `--remove-orphans`: Remove containers for services not defined in the Compose file
- :whale: `--force-recreate`: force Compose to stop and recreate all containers
- :whale: `--no-recreate`: force Compose to reuse existing containers
- :whale: `--pull`: Pull image before running ("always"|"missing"|"never")

Unimplemented `docker-compose up` (V1) flags: `--no-deps`, `--always-recreate-deps`,
`--no-start`, `--abort-on-container-exit`, `--attach-dependencies`, `--timeout`, `--renew-anon-volumes`, `--exit-code-from`
Expand Down
2 changes: 1 addition & 1 deletion pkg/composer/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (c *Composer) Create(ctx context.Context, opt CreateOptions, services []str
return err
}
for _, ps := range parsedServices {
if err := c.ensureServiceImage(ctx, ps, !opt.NoBuild, opt.Build, BuildOptions{}, false); err != nil {
if err := c.ensureServiceImage(ctx, ps, !opt.NoBuild, opt.Build, BuildOptions{}, false, ""); err != nil {
return err
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/composer/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func (c *Composer) runServices(ctx context.Context, parsedServices []*servicepar

// TODO: parallelize loop for ensuring images (make sure not to mess up tty)
for _, ps := range parsedServices {
if err := c.ensureServiceImage(ctx, ps, !ro.NoBuild, ro.ForceBuild, BuildOptions{}, ro.QuietPull); err != nil {
if err := c.ensureServiceImage(ctx, ps, !ro.NoBuild, ro.ForceBuild, BuildOptions{}, ro.QuietPull, ""); err != nil {
return err
}
}
Expand Down
1 change: 1 addition & 0 deletions pkg/composer/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type UpOptions struct {
ForceRecreate bool
NoRecreate bool
Scale map[string]int // map of service name to replicas
Pull string
}

func (opts UpOptions) recreateStrategy() string {
Expand Down
7 changes: 5 additions & 2 deletions pkg/composer/up_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (c *Composer) upServices(ctx context.Context, parsedServices []*servicepars

// TODO: parallelize loop for ensuring images (make sure not to mess up tty)
for _, ps := range parsedServices {
if err := c.ensureServiceImage(ctx, ps, !uo.NoBuild, uo.ForceBuild, BuildOptions{}, uo.QuietPull); err != nil {
if err := c.ensureServiceImage(ctx, ps, !uo.NoBuild, uo.ForceBuild, BuildOptions{}, uo.QuietPull, uo.Pull); err != nil {
return err
}
}
Expand Down Expand Up @@ -101,7 +101,7 @@ func (c *Composer) upServices(ctx context.Context, parsedServices []*servicepars
return nil
}

func (c *Composer) ensureServiceImage(ctx context.Context, ps *serviceparser.Service, allowBuild, forceBuild bool, bo BuildOptions, quiet bool) error {
func (c *Composer) ensureServiceImage(ctx context.Context, ps *serviceparser.Service, allowBuild, forceBuild bool, bo BuildOptions, quiet bool, pullModeArg string) error {
if ps.Build != nil && allowBuild {
if ps.Build.Force || forceBuild {
return c.buildServiceImage(ctx, ps.Image, ps.Build, ps.Unparsed.Platform, bo)
Expand All @@ -117,6 +117,9 @@ func (c *Composer) ensureServiceImage(ctx context.Context, ps *serviceparser.Ser
}

log.G(ctx).Infof("Ensuring image %s", ps.Image)
if pullModeArg != "" {
return c.EnsureImage(ctx, ps.Image, pullModeArg, ps.Unparsed.Platform, ps, quiet)
}
return c.EnsureImage(ctx, ps.Image, ps.PullMode, ps.Unparsed.Platform, ps, quiet)
}

Expand Down