From af40dfc2bf614aeb4191916cc2420068696eb776 Mon Sep 17 00:00:00 2001
From: José Guilherme Vanz <jvanz@jvanz.com>
Date: Tue, 29 Jun 2021 16:39:11 -0300
Subject: --infra-name command line argument
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Adds the new --infra-name command line argument allowing users to define
the name of the infra container

Issue #10794

Signed-off-by: José Guilherme Vanz <jvanz@jvanz.com>
---
 cmd/podman/pods/create.go                   |  7 +++++++
 docs/source/markdown/podman-pod-create.1.md |  4 ++++
 libpod/options.go                           | 26 ++++++++++++++++++++++++++
 libpod/pod.go                               |  1 +
 libpod/runtime_pod_infra_linux.go           |  6 +++++-
 pkg/api/handlers/types.go                   |  1 +
 pkg/domain/entities/pods.go                 |  2 ++
 pkg/specgen/generate/pod_create.go          |  4 ++++
 pkg/specgen/pod_validate.go                 |  3 +++
 pkg/specgen/podspecgen.go                   |  6 ++++++
 test/system/200-pod.bats                    | 17 ++++++++++++++++-
 11 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 0d299bb9c..abc47164b 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -86,6 +86,10 @@ func init() {
 	flags.String(infraCommandFlagName, containerConfig.Engine.InfraCommand, "The command to run on the infra container when the pod is started")
 	_ = createCommand.RegisterFlagCompletionFunc(infraCommandFlagName, completion.AutocompleteNone)
 
+	infraNameFlagName := "infra-name"
+	flags.StringVarP(&createOptions.InfraName, infraNameFlagName, "", "", "The name used as infra container name")
+	_ = createCommand.RegisterFlagCompletionFunc(infraNameFlagName, completion.AutocompleteNone)
+
 	labelFileFlagName := "label-file"
 	flags.StringSliceVar(&labelFile, labelFileFlagName, []string{}, "Read in a line delimited file of labels")
 	_ = createCommand.RegisterFlagCompletionFunc(labelFileFlagName, completion.AutocompleteDefault)
@@ -148,6 +152,9 @@ func create(cmd *cobra.Command, args []string) error {
 			return errors.New("cannot set infra-image without an infra container")
 		}
 		createOptions.InfraImage = ""
+		if createOptions.InfraName != "" {
+			return errors.New("cannot set infra-name without an infra container")
+		}
 
 		if cmd.Flag("share").Changed && share != "none" && share != "" {
 			return fmt.Errorf("cannot set share(%s) namespaces without an infra container", cmd.Flag("share").Value)
diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md
index fecdd8494..441995cb6 100644
--- a/docs/source/markdown/podman-pod-create.1.md
+++ b/docs/source/markdown/podman-pod-create.1.md
@@ -75,6 +75,10 @@ The command that will be run to start the infra container. Default: "/pause".
 
 The image that will be created for the infra container. Default: "k8s.gcr.io/pause:3.1".
 
+#### **--infra-name**=*name*
+
+The name that will be used for the pod's infra container.
+
 #### **--ip**=*ipaddr*
 
 Set a static IP for the pod's shared network.
diff --git a/libpod/options.go b/libpod/options.go
index bc563d60c..17a36008d 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -459,6 +459,19 @@ func WithDefaultInfraCommand(cmd string) RuntimeOption {
 	}
 }
 
+// WithDefaultInfraName sets the infra container name for a single pod.
+func WithDefaultInfraName(name string) RuntimeOption {
+	return func(rt *Runtime) error {
+		if rt.valid {
+			return define.ErrRuntimeFinalized
+		}
+
+		rt.config.Engine.InfraImage = name
+
+		return nil
+	}
+}
+
 // WithRenumber instructs libpod to perform a lock renumbering while
 // initializing. This will handle migrations from early versions of libpod with
 // file locks to newer versions with SHM locking, as well as changes in the
@@ -1787,6 +1800,19 @@ func WithInfraCommand(cmd []string) PodCreateOption {
 	}
 }
 
+// WithInfraName sets the infra container name for a single pod.
+func WithInfraName(name string) PodCreateOption {
+	return func(pod *Pod) error {
+		if pod.valid {
+			return define.ErrPodFinalized
+		}
+
+		pod.config.InfraContainer.InfraName = name
+
+		return nil
+	}
+}
+
 // WithPodName sets the name of the pod.
 func WithPodName(name string) PodCreateOption {
 	return func(pod *Pod) error {
diff --git a/libpod/pod.go b/libpod/pod.go
index c03059c82..62f5c9e5b 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -112,6 +112,7 @@ type InfraContainerConfig struct {
 	ExitCommand        []string              `json:"exitCommand,omitempty"`
 	InfraImage         string                `json:"infraImage,omitempty"`
 	InfraCommand       []string              `json:"infraCommand,omitempty"`
+	InfraName          string                `json:"infraName,omitempty"`
 	Slirp4netns        bool                  `json:"slirp4netns,omitempty"`
 	NetworkOptions     map[string][]string   `json:"network_options,omitempty"`
 	ResourceLimits     *specs.LinuxResources `json:"resource_limits,omitempty"`
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index 8342352ec..d4f861118 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -201,7 +201,11 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
 		g.AddLinuxSysctl(sysctlKey, sysctlVal)
 	}
 
-	containerName := p.ID()[:IDTruncLength] + "-infra"
+	containerName := p.config.InfraContainer.InfraName
+	if containerName == "" {
+		containerName = p.ID()[:IDTruncLength] + "-infra"
+	}
+	logrus.Infof("Infra container name %s", containerName)
 	options = append(options, r.WithPod(p))
 	options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName))
 	options = append(options, WithName(containerName))
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 59f948567..3cc10d70f 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -133,6 +133,7 @@ type PodCreateConfig struct {
 	Infra        bool     `json:"infra"`
 	InfraCommand string   `json:"infra-command"`
 	InfraImage   string   `json:"infra-image"`
+	InfraName    string   `json:"infra-name"`
 	Labels       []string `json:"labels"`
 	Publish      []string `json:"publish"`
 	Share        string   `json:"share"`
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index a0a2a1790..68e335f8d 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -112,6 +112,7 @@ type PodCreateOptions struct {
 	Hostname           string
 	Infra              bool
 	InfraImage         string
+	InfraName          string
 	InfraCommand       string
 	InfraConmonPidFile string
 	Labels             map[string]string
@@ -172,6 +173,7 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
 		s.InfraConmonPidFile = p.InfraConmonPidFile
 	}
 	s.InfraImage = p.InfraImage
+	s.InfraName = p.InfraName
 	s.SharedNamespaces = p.Share
 	s.PodCreateCommand = p.CreateCommand
 
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 4ffd8a37f..aab29499e 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -98,6 +98,10 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
 		options = append(options, libpod.WithInfraImage(p.InfraImage))
 	}
 
+	if len(p.InfraName) > 0 {
+		options = append(options, libpod.WithInfraName(p.InfraName))
+	}
+
 	if len(p.InfraCommand) > 0 {
 		options = append(options, libpod.WithInfraCommand(p.InfraCommand))
 	}
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index c746bcd1a..bca7b6dbe 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -36,6 +36,9 @@ func (p *PodSpecGenerator) Validate() error {
 		if len(p.InfraImage) > 0 {
 			return exclusivePodOptions("NoInfra", "InfraImage")
 		}
+		if len(p.InfraName) > 0 {
+			return exclusivePodOptions("NoInfra", "InfraName")
+		}
 		if len(p.SharedNamespaces) > 0 {
 			return exclusivePodOptions("NoInfra", "SharedNamespaces")
 		}
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 319345c71..02237afe9 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -43,6 +43,12 @@ type PodBasicConfig struct {
 	// Conflicts with NoInfra=true.
 	// Optional.
 	InfraImage string `json:"infra_image,omitempty"`
+	// InfraName is the name that will be used for the infra container.
+	// If not set, the default set in the Libpod configuration file will be
+	// used.
+	// Conflicts with NoInfra=true.
+	// Optional.
+	InfraName string `json:"infra_name,omitempty"`
 	// SharedNamespaces instructs the pod to share a set of namespaces.
 	// Shared namespaces will be joined (by default) by every container
 	// which joins the pod.
diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats
index 054eda908..266f91298 100644
--- a/test/system/200-pod.bats
+++ b/test/system/200-pod.bats
@@ -205,6 +205,7 @@ function random_ip() {
     # entrypoint to confirm that --infra-command will override.
     local infra_image="infra_$(random_string 10 | tr A-Z a-z)"
     local infra_command="/pause_$(random_string 10)"
+    local infra_name="infra_container_$(random_string 10 | tr A-Z a-z)"
     run_podman build -t $infra_image - << EOF
 FROM $IMAGE
 RUN ln /home/podman/pause $infra_command
@@ -225,7 +226,8 @@ EOF
                --publish    "$port_out:$port_in"         \
                --label      "${labelname}=${labelvalue}" \
                --infra-image   "$infra_image"            \
-               --infra-command "$infra_command"
+               --infra-command "$infra_command"          \
+               --infra-name "$infra_name"
     pod_id="$output"
 
     # Check --pod-id-file
@@ -237,6 +239,9 @@ EOF
     # confirm that entrypoint is what we set
     run_podman container inspect --format '{{.Config.Entrypoint}}' $infra_cid
     is "$output" "$infra_command" "infra-command took effect"
+    # confirm that infra container name is set
+    run_podman container inspect --format '{{.Name}}' $infra_cid
+    is "$output" "$infra_name" "infra-name took effect"
 
     # Check each of the options
     if [ -n "$mac_option" ]; then
@@ -310,6 +315,16 @@ EOF
     run_podman rm $cid
     run_podman pod rm -f mypod
     run_podman rmi $infra_image
+
+}
+
+@test "podman pod create should fail when infra-name is already in use" {
+    local infra_name="infra_container_$(random_string 10 | tr A-Z a-z)"
+    run_podman pod create --infra-name "$infra_name"
+    run_podman '?' pod create --infra-name "$infra_name"
+    if [ $status -eq 0 ]; then
+        die "Podman should fail when user try to create two pods with the same infra-name value"
+    fi
 }
 
 # vim: filetype=sh
-- 
cgit v1.2.3-54-g00ecf