pod create --replace

Add a `--replace` flag to the `pod create` command.  If another pod 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 pod may not be removed by a sytemd unit anymore.  The
`--replace` flag allows for supporting crashes.

Note that the `--replace` flag does not require the `--name` flag to be
set, so it can be set unconditionally in `podman generate systemd`.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg
2020-06-15 13:49:36 +02:00
parent fa3b8a75c4
commit fe488b5f11
5 changed files with 51 additions and 6 deletions

View File

@ -39,6 +39,7 @@ var (
createOptions entities.PodCreateOptions
labels, labelFile []string
podIDFile string
replace bool
share string
)
@ -61,6 +62,7 @@ func init() {
flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
flags.StringVarP(&createOptions.Hostname, "hostname", "", "", "Set a hostname to the pod")
flags.StringVar(&podIDFile, "pod-id-file", "", "Write the pod ID to the file")
flags.BoolVar(&replace, "replace", false, "If a pod with the same exists, replace it")
flags.StringVar(&share, "share", specgen.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
flags.SetNormalizeFunc(aliasNetworkFlag)
}
@ -147,6 +149,12 @@ func create(cmd *cobra.Command, args []string) error {
}
}
if replace {
if err := replacePod(createOptions.Name); err != nil {
return err
}
}
response, err := registry.ContainerEngine().PodCreate(context.Background(), createOptions)
if err != nil {
return err
@ -159,3 +167,14 @@ func create(cmd *cobra.Command, args []string) error {
fmt.Println(response.Id)
return nil
}
func replacePod(name string) error {
if len(name) == 0 {
return errors.New("cannot replace pod without --name being set")
}
rmOptions := entities.PodRmOptions{
Force: true, // stop and remove pod
Ignore: true, // ignore if pod doesn't exist
}
return removePods([]string{name}, rmOptions, false)
}

View File

@ -58,24 +58,30 @@ func init() {
}
func rm(cmd *cobra.Command, args []string) error {
var (
errs utils.OutputErrors
)
ids, err := common.ReadPodIDFiles(rmOptions.PodIDFiles)
if err != nil {
return err
}
args = append(args, ids...)
return removePods(args, rmOptions.PodRmOptions, true)
}
responses, err := registry.ContainerEngine().PodRm(context.Background(), args, rmOptions.PodRmOptions)
// removePods removes the specified pods (names or IDs). Allows for sharing
// pod-removal logic across commands.
func removePods(namesOrIDs []string, rmOptions entities.PodRmOptions, printIDs bool) error {
var errs utils.OutputErrors
responses, err := registry.ContainerEngine().PodRm(context.Background(), namesOrIDs, rmOptions)
if err != nil {
return err
}
// in the cli, first we print out all the successful attempts
for _, r := range responses {
if r.Err == nil {
fmt.Println(r.Id)
if printIDs {
fmt.Println(r.Id)
}
} else {
errs = append(errs, r.Err)
}

View File

@ -3118,6 +3118,7 @@ _podman_pod_create() {
--help
-h
--infra
--replace
"
_complete_ "$options_with_args" "$boolean_options"
}

View File

@ -102,6 +102,10 @@ Use `podman port` to see the actual mapping: `podman port CONTAINER $CONTAINERPO
NOTE: This cannot be modified once the pod is created.
**--replace**=**true**|**false**
If another pod with the same name already exists, replace and remove it. The default is **false**.
**--share**=*namespace*
A comma delimited list of kernel namespaces to share. If none or "" is specified, no namespaces will be shared. The namespaces to choose from are ipc, net, pid, user, uts.

View File

@ -305,4 +305,19 @@ var _ = Describe("Podman pod create", func() {
data := check.InspectPodToJSON()
Expect(data.ID).To(Equal(string(id)))
})
It("podman pod create --replace", func() {
// Make sure we error out with --name.
session := podmanTest.Podman([]string{"pod", "create", "--replace", ALPINE, "/bin/sh"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
// Create and replace 5 times in a row the "same" pod.
podName := "testCtr"
for i := 0; i < 5; i++ {
session = podmanTest.Podman([]string{"pod", "create", "--replace", "--name", podName})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
}
})
})