mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
{create,run} --replace
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 #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 <rothberg@redhat.com>
This commit is contained in:
@ -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", "",
|
||||
|
@ -76,6 +76,7 @@ type ContainerCLIOpts struct {
|
||||
ReadOnly bool
|
||||
ReadOnlyTmpFS bool
|
||||
Restart string
|
||||
Replace bool
|
||||
Rm bool
|
||||
RootFS bool
|
||||
SecurityOpt []string
|
||||
|
@ -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
|
||||
@ -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")
|
||||
|
@ -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
|
||||
)
|
||||
@ -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
|
||||
@ -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")
|
||||
}
|
||||
if setExit {
|
||||
setExitCode(r.Err)
|
||||
}
|
||||
errs = append(errs, r.Err)
|
||||
} else {
|
||||
fmt.Println(r.Id)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -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))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user