container-{create,run}: add `--pod-id-file`

Allow containers to join an existing pod via the `--pod-id-file` which
is already supported by a number of `podman-pod` subcommands.  Also add
tests to make sure it's working and to prevent future regressions.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg 2020-05-29 10:35:22 +02:00
parent 7d71d24440
commit cf89bb6711
12 changed files with 95 additions and 27 deletions

View File

@ -338,6 +338,11 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
"pod", "",
"Run container in an existing pod",
)
createFlags.StringVar(
&cf.PodIDFile,
"pod-id-file", "",
"Read the pod ID from the file",
)
createFlags.BoolVar(
&cf.Privileged,
"privileged", false,

View File

@ -68,6 +68,7 @@ type ContainerCLIOpts struct {
PID string
PIDsLimit int64
Pod string
PodIDFile string
Privileged bool
PublishAll bool
Pull string

View File

@ -254,6 +254,17 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.PublishExposedPorts = c.PublishAll
s.Pod = c.Pod
if len(c.PodIDFile) > 0 {
if len(s.Pod) > 0 {
return errors.New("Cannot specify both --pod and --pod-id-file")
}
podID, err := ReadPodIDFile(c.PodIDFile)
if err != nil {
return err
}
s.Pod = podID
}
expose, err := createExpose(c.Expose)
if err != nil {
return err

View File

@ -1,6 +1,7 @@
package common
import (
"io/ioutil"
"net"
"strconv"
"strings"
@ -10,6 +11,30 @@ import (
"github.com/sirupsen/logrus"
)
// ReadPodIDFile reads the specified file and returns its content (i.e., first
// line).
func ReadPodIDFile(path string) (string, error) {
content, err := ioutil.ReadFile(path)
if err != nil {
return "", errors.Wrap(err, "error reading pod ID file")
}
return strings.Split(string(content), "\n")[0], nil
}
// ReadPodIDFiles reads the specified files and returns their content (i.e.,
// first line).
func ReadPodIDFiles(files []string) ([]string, error) {
ids := []string{}
for _, file := range files {
id, err := ReadPodIDFile(file)
if err != nil {
return nil, err
}
ids = append(ids, id)
}
return ids, nil
}
// createExpose parses user-provided exposed port definitions and converts them
// into SpecGen format.
// TODO: The SpecGen format should really handle ranges more sanely - we could

View File

@ -1,23 +0,0 @@
package pods
import (
"io/ioutil"
"strings"
"github.com/pkg/errors"
)
// readPodIDFiles reads the specified files and returns their content (i.e.,
// first line).
func readPodIDFiles(files []string) ([]string, error) {
ids := []string{}
for _, podFile := range files {
content, err := ioutil.ReadFile(podFile)
if err != nil {
return nil, errors.Wrap(err, "error reading pod ID file")
}
id := strings.Split(string(content), "\n")[0]
ids = append(ids, id)
}
return ids, nil
}

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
@ -61,7 +62,7 @@ func rm(cmd *cobra.Command, args []string) error {
errs utils.OutputErrors
)
ids, err := readPodIDFiles(rmOptions.PodIDFiles)
ids, err := common.ReadPodIDFiles(rmOptions.PodIDFiles)
if err != nil {
return err
}

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
@ -61,7 +62,7 @@ func start(cmd *cobra.Command, args []string) error {
errs utils.OutputErrors
)
ids, err := readPodIDFiles(startOptions.PodIDFiles)
ids, err := common.ReadPodIDFiles(startOptions.PodIDFiles)
if err != nil {
return err
}

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/containers/libpod/cmd/podman/common"
"github.com/containers/libpod/cmd/podman/parse"
"github.com/containers/libpod/cmd/podman/registry"
"github.com/containers/libpod/cmd/podman/utils"
@ -68,7 +69,7 @@ func stop(cmd *cobra.Command, args []string) error {
stopOptions.Timeout = int(stopOptions.TimeoutCLI)
}
ids, err := readPodIDFiles(stopOptions.PodIDFiles)
ids, err := common.ReadPodIDFiles(stopOptions.PodIDFiles)
if err != nil {
return err
}

View File

@ -2102,6 +2102,7 @@ _podman_container_run() {
--pid
--pids-limit
--pod
--pod-id-file
--publish -p
--pull
--runtime
@ -2206,7 +2207,7 @@ _podman_container_run() {
__podman_complete_capabilities
return
;;
--cidfile|--env-file|--init-path|--label-file)
--cidfile|--env-file|--init-path|--label-file|--pod-id-file)
_filedir
return
;;

View File

@ -593,6 +593,10 @@ Tune the container's pids limit. Set `0` to have unlimited pids for the containe
Run container in an existing pod. If you want Podman to make the pod for you, preference the pod name with `new:`.
To make a pod with more granular options, use the `podman pod create` command before creating a container.
**--pod-id-file**=*path*
Run container in an existing pod and read the pod's ID from the specified file. If a container is run with a pod, and the pod has an infra-container, the infra-container will be started before the container is.
**--privileged**=*true|false*
Give extended privileges to this container. The default is *false*.

View File

@ -605,6 +605,10 @@ Run container in an existing pod. If you want Podman to make the pod for you, pr
To make a pod with more granular options, use the **podman pod create** command before creating a container.
If a container is run with a pod, and the pod has an infra-container, the infra-container will be started before the container is.
**--pod-id-file**=*path*
Run container in an existing pod and read the pod's ID from the specified file. If a container is run with a pod, and the pod has an infra-container, the infra-container will be started before the container is.
**--privileged**=**true**|**false**
Give extended privileges to this container. The default is **false**.

View File

@ -2,6 +2,7 @@ package integration
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
@ -221,6 +222,42 @@ var _ = Describe("Podman create", func() {
Expect(match).To(BeTrue())
})
It("podman create --pod-id-file", func() {
// First, make sure that --pod and --pod-id-file yield an error
// if used together.
session := podmanTest.Podman([]string{"create", "--pod", "foo", "--pod-id-file", "bar", ALPINE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(125))
tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil())
defer os.RemoveAll(tmpDir)
podName := "rudoplh"
ctrName := "prancer"
podIDFile := tmpDir + "pod-id-file"
// Now, let's create a pod with --pod-id-file.
session = podmanTest.Podman([]string{"pod", "create", "--pod-id-file", podIDFile, "--name", podName})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "inspect", podName})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.IsJSONOutputValid()).To(BeTrue())
podData := session.InspectPodToJSON()
// Finally we can create a container with --pod-id-file and do
// some checks to make sure it's working as expected.
session = podmanTest.Podman([]string{"create", "--pod-id-file", podIDFile, "--name", ctrName, ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
ctrJSON := podmanTest.InspectContainer(ctrName)
Expect(podData.ID).To(Equal(ctrJSON[0].Pod)) // Make sure the container's pod matches the pod's ID
})
It("podman run entrypoint and cmd test", func() {
name := "test101"
create := podmanTest.Podman([]string{"create", "--name", name, redis})