Skip to content

Commit

Permalink
{create,run} --replace
Browse files Browse the repository at this point in the history
Add a `--replace` flag to the `container {create,run}` commands.
If another container with the same name already exists, it will
be replaced and removed.

Adding this flag is motivated by containers#5485 to make running Podman in systemd
units (or any other scripts/automation) more robust.  In case of a
crash, a container may not be removed by a sytemd unit anymore.  The
`--replace` flag allows for supporting crashes.

Signed-off-by: Valentin Rothberg <[email protected]>
  • Loading branch information
vrothberg committed Jun 15, 2020
1 parent f4c3b71 commit fa3b8a7
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 3 deletions.
5 changes: 5 additions & 0 deletions cmd/podman/common/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"read-only-tmpfs", true,
"When running containers in read-only mode mount a read-write tmpfs on /run, /tmp and /var/tmp",
)
createFlags.BoolVar(
&cf.Replace,
"replace", false,
`If a container with the same name exists, replace it`,
)
createFlags.StringVar(
&cf.Restart,
"restart", "",
Expand Down
1 change: 1 addition & 0 deletions cmd/podman/common/create_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type ContainerCLIOpts struct {
ReadOnly bool
ReadOnlyTmpFS bool
Restart string
Replace bool
Rm bool
RootFS bool
SecurityOpt []string
Expand Down
17 changes: 17 additions & 0 deletions cmd/podman/containers/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ func create(cmd *cobra.Command, args []string) error {
return err
}

if cliVals.Replace {
if err := replaceContainer(cliVals.Name); err != nil {
return err
}
}

report, err := registry.ContainerEngine().ContainerCreate(registry.GetContext(), s)
if err != nil {
return err
Expand All @@ -138,6 +144,17 @@ func create(cmd *cobra.Command, args []string) error {
return nil
}

func replaceContainer(name string) error {
if len(name) == 0 {
return errors.New("cannot replace container without --name being set")
}
rmOptions := entities.RmOptions{
Force: true, // force stop & removal
Ignore: true, // ignore errors when a container doesn't exit
}
return removeContainers([]string{name}, rmOptions, false)
}

func createInit(c *cobra.Command) error {
if c.Flag("privileged").Changed && c.Flag("security-opt").Changed {
logrus.Warn("setting security options with --privileged has no effect")
Expand Down
16 changes: 13 additions & 3 deletions cmd/podman/containers/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ func init() {
}

func rm(cmd *cobra.Command, args []string) error {
return removeContainers(args, rmOptions, true)
}

// removeContainers will remove the specified containers (names or IDs).
// Allows for sharing removal logic across commands. If setExit is set,
// removeContainers will set the exit code according to the `podman-rm` man
// page.
func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit bool) error {
var (
errs utils.OutputErrors
)
Expand All @@ -96,9 +104,9 @@ func rm(cmd *cobra.Command, args []string) error {
return errors.Errorf("--storage conflicts with --volumes, --all, --latest, --ignore and --cidfile")
}
}
responses, err := registry.ContainerEngine().ContainerRm(context.Background(), args, rmOptions)
responses, err := registry.ContainerEngine().ContainerRm(context.Background(), namesOrIDs, rmOptions)
if err != nil {
if len(args) < 2 {
if setExit && len(namesOrIDs) < 2 {
setExitCode(err)
}
return err
Expand All @@ -109,7 +117,9 @@ func rm(cmd *cobra.Command, args []string) error {
if errors.Cause(err) == define.ErrWillDeadlock {
logrus.Errorf("Potential deadlock detected - please run 'podman system renumber' to resolve")
}
setExitCode(r.Err)
if setExit {
setExitCode(r.Err)
}
errs = append(errs, r.Err)
} else {
fmt.Println(r.Id)
Expand Down
6 changes: 6 additions & 0 deletions cmd/podman/containers/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ func run(cmd *cobra.Command, args []string) error {
}
}

if cliVals.Replace {
if err := replaceContainer(cliVals.Name); err != nil {
return err
}
}

// If -i is not set, clear stdin
if !cliVals.Interactive {
runOpts.InputStream = nil
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,10 @@ its root filesystem mounted as read only prohibiting any writes.

If container is running in --read-only mode, then mount a read-write tmpfs on /run, /tmp, and /var/tmp. The default is *true*

**--replace**=**true**|**false**

If another container with the same name already exists, replace and remove it. The default is **false**.

**--restart**=*policy*

Restart policy to follow when containers exit.
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-run.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,10 @@ its root filesystem mounted as read only prohibiting any writes.

If container is running in **--read-only** mode, then mount a read-write tmpfs on _/run_, _/tmp_, and _/var/tmp_. The default is **true**.

**--replace**=**true**|**false**

If another container with the same name already exists, replace and remove it. The default is **false**.

**--restart**=*policy*

Restart policy to follow when containers exit.
Expand Down
15 changes: 15 additions & 0 deletions test/e2e/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,4 +429,19 @@ var _ = Describe("Podman create", func() {
Expect(len(data)).To(Equal(1))
Expect(data[0].HostConfig.NanoCpus).To(Equal(int64(nanoCPUs)))
})

It("podman create --replace", func() {
// Make sure we error out with --name.
session := podmanTest.Podman([]string{"create", "--replace", ALPINE, "/bin/sh"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))

// Create and replace 5 times in a row the "same" container.
ctrName := "testCtr"
for i := 0; i < 5; i++ {
session = podmanTest.Podman([]string{"create", "--replace", "--name", ctrName, ALPINE, "/bin/sh"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
}
})
})
15 changes: 15 additions & 0 deletions test/e2e/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,4 +931,19 @@ USER mail`
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})

It("podman run --replace", func() {
// Make sure we error out with --name.
session := podmanTest.Podman([]string{"create", "--replace", ALPINE, "/bin/sh"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))

// Run and replace 5 times in a row the "same" container.
ctrName := "testCtr"
for i := 0; i < 5; i++ {
session := podmanTest.Podman([]string{"run", "--detach", "--replace", "--name", ctrName, ALPINE, "/bin/sh"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
}
})
})

0 comments on commit fa3b8a7

Please sign in to comment.