summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/images/list.go15
-rw-r--r--cmd/podman/images/pull.go13
-rw-r--r--cmd/podman/pods/create.go19
-rw-r--r--cmd/podman/root.go4
-rw-r--r--cmd/podman/system/version.go5
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--libpod/image/utils.go27
-rw-r--r--libpod/options.go30
-rw-r--r--libpod/pod.go2
-rw-r--r--libpod/rootless_cni_linux.go2
-rw-r--r--libpod/runtime_pod_infra_linux.go25
-rw-r--r--pkg/api/handlers/libpod/images.go120
-rw-r--r--pkg/api/handlers/libpod/images_pull.go193
-rw-r--r--pkg/bindings/images/images.go45
-rw-r--r--pkg/bindings/images/pull.go98
-rw-r--r--pkg/domain/entities/images.go17
-rw-r--r--pkg/domain/infra/abi/images_list.go24
-rw-r--r--pkg/domain/infra/abi/play.go5
-rw-r--r--pkg/domain/infra/runtime_libpod.go17
-rw-r--r--pkg/specgen/generate/pod_create.go9
-rw-r--r--pkg/specgen/pod_validate.go7
-rw-r--r--test/e2e/images_test.go32
-rw-r--r--test/e2e/play_kube_test.go74
-rw-r--r--test/e2e/pod_create_test.go76
-rw-r--r--vendor/modules.txt2
26 files changed, 587 insertions, 280 deletions
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index 043871a8c..ffb341fc4 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -184,13 +184,26 @@ func sortImages(imageS []*entities.ImageSummary) ([]imageReporter, error) {
for _, e := range imageS {
var h imageReporter
if len(e.RepoTags) > 0 {
+ tagged := []imageReporter{}
+ untagged := []imageReporter{}
for _, tag := range e.RepoTags {
h.ImageSummary = *e
h.Repository, h.Tag, err = tokenRepoTag(tag)
if err != nil {
return nil, errors.Wrapf(err, "error parsing repository tag %q:", tag)
}
- imgs = append(imgs, h)
+ if h.Tag == "<none>" {
+ untagged = append(untagged, h)
+ } else {
+ tagged = append(tagged, h)
+ }
+ }
+ // Note: we only want to display "<none>" if we
+ // couldn't find any tagged name in RepoTags.
+ if len(tagged) > 0 {
+ imgs = append(imgs, tagged...)
+ } else {
+ imgs = append(imgs, untagged[0])
}
} else {
h.ImageSummary = *e
diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go
index d86f9800c..448543b4d 100644
--- a/cmd/podman/images/pull.go
+++ b/cmd/podman/images/pull.go
@@ -44,10 +44,10 @@ var (
// child of the images command.
imagesPullCmd = &cobra.Command{
Use: pullCmd.Use,
+ Args: pullCmd.Args,
Short: pullCmd.Short,
Long: pullCmd.Long,
RunE: pullCmd.RunE,
- Args: cobra.ExactArgs(1),
Example: `podman image pull imageName
podman image pull fedora:latest`,
}
@@ -77,8 +77,6 @@ func init() {
// pullFlags set the flags for the pull command.
func pullFlags(flags *pflag.FlagSet) {
flags.BoolVar(&pullOptions.AllTags, "all-tags", false, "All tagged images in the repository will be pulled")
- flags.StringVar(&pullOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
- flags.StringVar(&pullOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
flags.StringVar(&pullOptions.CredentialsCLI, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
flags.StringVar(&pullOptions.OverrideArch, "override-arch", "", "Use `ARCH` instead of the architecture of the machine for choosing images")
flags.StringVar(&pullOptions.OverrideOS, "override-os", "", "Use `OS` instead of the running OS for choosing images")
@@ -86,12 +84,11 @@ func pullFlags(flags *pflag.FlagSet) {
flags.Bool("disable-content-trust", false, "This is a Docker specific option and is a NOOP")
flags.BoolVarP(&pullOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
flags.StringVar(&pullOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
- flags.BoolVar(&pullOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
- if registry.IsRemote() {
- _ = flags.MarkHidden("authfile")
- _ = flags.MarkHidden("cert-dir")
- _ = flags.MarkHidden("tls-verify")
+ if !registry.IsRemote() {
+ flags.StringVar(&pullOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&pullOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
+ flags.BoolVar(&pullOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
_ = flags.MarkHidden("signature-policy")
}
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 603ddcaca..d8d32b930 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -55,8 +55,8 @@ func init() {
flags.StringVar(&createOptions.CGroupParent, "cgroup-parent", "", "Set parent cgroup for the pod")
flags.BoolVar(&createOptions.Infra, "infra", true, "Create an infra container associated with the pod to share namespaces with")
flags.StringVar(&createOptions.InfraConmonPidFile, "infra-conmon-pidfile", "", "Path to the file that will receive the POD of the infra container's conmon")
- flags.StringVar(&createOptions.InfraImage, "infra-image", containerConfig.Engine.InfraImage, "The image of the infra container to associate with the pod")
- flags.StringVar(&createOptions.InfraCommand, "infra-command", containerConfig.Engine.InfraCommand, "The command to run on the infra container when the pod is started")
+ flags.String("infra-image", containerConfig.Engine.InfraImage, "The image of the infra container to associate with the pod")
+ flags.String("infra-command", containerConfig.Engine.InfraCommand, "The command to run on the infra container when the pod is started")
flags.StringSliceVar(&labelFile, "label-file", []string{}, "Read in a line delimited file of labels")
flags.StringSliceVarP(&labels, "label", "l", []string{}, "Set metadata on pod (default [])")
flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
@@ -92,7 +92,6 @@ func create(cmd *cobra.Command, args []string) error {
if cmd.Flag("infra-command").Changed {
return errors.New("cannot set infra-command without an infra container")
}
- createOptions.InfraCommand = ""
if cmd.Flag("infra-image").Changed {
return errors.New("cannot set infra-image without an infra container")
}
@@ -104,6 +103,20 @@ func create(cmd *cobra.Command, args []string) error {
createOptions.Share = nil
} else {
createOptions.Share = strings.Split(share, ",")
+ if cmd.Flag("infra-command").Changed {
+ // Only send content to server side if user changed defaults
+ createOptions.InfraCommand, err = cmd.Flags().GetString("infra-command")
+ if err != nil {
+ return err
+ }
+ }
+ if cmd.Flag("infra-image").Changed {
+ // Only send content to server side if user changed defaults
+ createOptions.InfraImage, err = cmd.Flags().GetString("infra-image")
+ if err != nil {
+ return err
+ }
+ }
}
if cmd.Flag("pod-id-file").Changed {
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index d079018a0..8def7112f 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -80,10 +80,6 @@ func init() {
)
rootFlags(rootCmd, registry.PodmanConfig())
-
- // "version" is a local flag to avoid collisions with sub-commands that use "-v"
- var dummyVersion bool
- rootCmd.Flags().BoolVarP(&dummyVersion, "version", "v", false, "Version of Podman")
}
func Execute() {
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index edc860d0e..5f39b4820 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -47,12 +47,9 @@ func version(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- _, err = io.WriteString(os.Stdout, s)
+ _, err = io.WriteString(os.Stdout, s+"\n")
return err
case cmd.Flag("format").Changed:
- if !strings.HasSuffix(versionFormat, "\n") {
- versionFormat += "\n"
- }
out := formats.StdoutTemplate{Output: versions, Template: versionFormat}
err := out.Out()
if err != nil {
diff --git a/go.mod b/go.mod
index fcfd199b9..f923ce21f 100644
--- a/go.mod
+++ b/go.mod
@@ -62,7 +62,7 @@ require (
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed
k8s.io/api v0.0.0-20190620084959-7cf5895f2711
- k8s.io/apimachinery v0.19.1
+ k8s.io/apimachinery v0.19.2
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
)
diff --git a/go.sum b/go.sum
index 7eb8fe654..320c6263a 100644
--- a/go.sum
+++ b/go.sum
@@ -640,8 +640,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
k8s.io/api v0.0.0-20190620084959-7cf5895f2711 h1:BblVYz/wE5WtBsD/Gvu54KyBUTJMflolzc5I2DTvh50=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
-k8s.io/apimachinery v0.19.1 h1:cwsxZazM/LA9aUsBaL4bRS5ygoM6bYp8dFk22DSYQa4=
-k8s.io/apimachinery v0.19.1/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
+k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc=
+k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
diff --git a/libpod/image/utils.go b/libpod/image/utils.go
index b7ea63c66..918314476 100644
--- a/libpod/image/utils.go
+++ b/libpod/image/utils.go
@@ -86,33 +86,6 @@ func hasTransport(image string) bool {
return strings.Contains(image, "://")
}
-// ReposToMap parses the specified repotags and returns a map with repositories
-// as keys and the corresponding arrays of tags or digests-as-strings as values.
-func ReposToMap(names []string) (map[string][]string, error) {
- // map format is repo -> []tag-or-digest
- repos := make(map[string][]string)
- for _, name := range names {
- var repository, tag string
- if len(name) > 0 {
- named, err := reference.ParseNormalizedNamed(name)
- if err != nil {
- return nil, err
- }
- repository = named.Name()
- if ref, ok := named.(reference.NamedTagged); ok {
- tag = ref.Tag()
- } else if ref, ok := named.(reference.Canonical); ok {
- tag = ref.Digest().String()
- }
- }
- repos[repository] = append(repos[repository], tag)
- }
- if len(repos) == 0 {
- repos["<none>"] = []string{"<none>"}
- }
- return repos, nil
-}
-
// GetAdditionalTags returns a list of reference.NamedTagged for the
// additional tags given in images
func GetAdditionalTags(images []string) ([]reference.NamedTagged, error) {
diff --git a/libpod/options.go b/libpod/options.go
index d592124bc..f7b3419e5 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1659,6 +1659,36 @@ func WithUmask(umask string) CtrCreateOption {
// Pod Creation Options
+// WithInfraImage sets the infra image for libpod.
+// An infra image is used for inter-container kernel
+// namespace sharing within a pod. Typically, an infra
+// container is lightweight and is there to reap
+// zombie processes within its pid namespace.
+func WithInfraImage(img string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ pod.config.InfraContainer.InfraImage = img
+
+ return nil
+ }
+}
+
+// WithInfraCommand sets the command to
+// run on pause container start up.
+func WithInfraCommand(cmd []string) PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ pod.config.InfraContainer.InfraCommand = cmd
+ 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 422966b94..709184008 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -105,6 +105,8 @@ type InfraContainerConfig struct {
HostAdd []string `json:"hostsAdd,omitempty"`
Networks []string `json:"networks,omitempty"`
ExitCommand []string `json:"exitCommand,omitempty"`
+ InfraImage string `json:"infraImage,omitempty"`
+ InfraCommand []string `json:"infraCommand,omitempty"`
}
// ID retrieves the pod's ID
diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go
index 31097dd16..7feec6b44 100644
--- a/libpod/rootless_cni_linux.go
+++ b/libpod/rootless_cni_linux.go
@@ -255,7 +255,7 @@ func startRootlessCNIInfraContainer(ctx context.Context, r *Runtime) (*Container
Destination: "/etc/cni/net.d",
Type: "bind",
Source: r.config.Network.NetworkConfigDir,
- Options: []string{"ro"},
+ Options: []string{"ro", "bind"},
}
g.AddMount(etcCNINetD)
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index b2f21d946..164068638 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -36,22 +36,26 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
isRootless := rootless.IsRootless()
- entryCmd := []string{r.config.Engine.InfraCommand}
+ entrypointSet := len(p.config.InfraContainer.InfraCommand) > 0
+ entryPoint := p.config.InfraContainer.InfraCommand
+ entryCmd := []string{}
var options []CtrCreateOption
// I've seen circumstances where config is being passed as nil.
// Let's err on the side of safety and make sure it's safe to use.
if config != nil {
- setEntrypoint := false
// default to entrypoint in image if there is one
- if len(config.Entrypoint) > 0 {
- entryCmd = config.Entrypoint
- setEntrypoint = true
+ if !entrypointSet {
+ if len(config.Entrypoint) > 0 {
+ entrypointSet = true
+ entryPoint = config.Entrypoint
+ entryCmd = config.Entrypoint
+ }
}
if len(config.Cmd) > 0 {
// We can't use the default pause command, since we're
// sourcing from the image. If we didn't already set an
// entrypoint, set one now.
- if !setEntrypoint {
+ if !entrypointSet {
// Use the Docker default "/bin/sh -c"
// entrypoint, as we're overriding command.
// If an image doesn't want this, it can
@@ -136,6 +140,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName))
options = append(options, WithName(containerName))
options = append(options, withIsInfra())
+ if entrypointSet {
+ options = append(options, WithEntrypoint(entryPoint))
+ }
if len(p.config.InfraContainer.ConmonPidFile) > 0 {
options = append(options, WithConmonPidFile(p.config.InfraContainer.ConmonPidFile))
}
@@ -151,7 +158,11 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container,
return nil, define.ErrRuntimeStopped
}
- newImage, err := r.ImageRuntime().New(ctx, r.config.Engine.InfraImage, "", "", nil, nil, image.SigningOptions{}, nil, util.PullImageMissing)
+ img := p.config.InfraContainer.InfraImage
+ if img == "" {
+ img = r.config.Engine.InfraImage
+ }
+ newImage, err := r.ImageRuntime().New(ctx, img, "", "", nil, nil, image.SigningOptions{}, nil, util.PullImageMissing)
if err != nil {
return nil, err
}
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 1da41ad88..bc1bdc287 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -11,8 +11,6 @@ import (
"strings"
"github.com/containers/buildah"
- "github.com/containers/image/v5/docker"
- "github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v2/libpod"
@@ -25,7 +23,6 @@ import (
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/abi"
"github.com/containers/podman/v2/pkg/errorhandling"
- "github.com/containers/podman/v2/pkg/util"
utils2 "github.com/containers/podman/v2/utils"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -400,123 +397,6 @@ func ImagesImport(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusOK, entities.ImageImportReport{Id: importedImage})
}
-// ImagesPull is the v2 libpod endpoint for pulling images. Note that the
-// mandatory `reference` must be a reference to a registry (i.e., of docker
-// transport or be normalized to one). Other transports are rejected as they
-// do not make sense in a remote context.
-func ImagesPull(w http.ResponseWriter, r *http.Request) {
- runtime := r.Context().Value("runtime").(*libpod.Runtime)
- decoder := r.Context().Value("decoder").(*schema.Decoder)
- query := struct {
- Reference string `schema:"reference"`
- OverrideOS string `schema:"overrideOS"`
- OverrideArch string `schema:"overrideArch"`
- OverrideVariant string `schema:"overrideVariant"`
- TLSVerify bool `schema:"tlsVerify"`
- AllTags bool `schema:"allTags"`
- }{
- TLSVerify: true,
- }
-
- if err := decoder.Decode(&query, r.URL.Query()); err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
- return
- }
-
- if len(query.Reference) == 0 {
- utils.InternalServerError(w, errors.New("reference parameter cannot be empty"))
- return
- }
-
- imageRef, err := utils.ParseDockerReference(query.Reference)
- if err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "image destination %q is not a docker-transport reference", query.Reference))
- return
- }
-
- // Trim the docker-transport prefix.
- rawImage := strings.TrimPrefix(query.Reference, fmt.Sprintf("%s://", docker.Transport.Name()))
-
- // all-tags doesn't work with a tagged reference, so let's check early
- namedRef, err := reference.Parse(rawImage)
- if err != nil {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Wrapf(err, "error parsing reference %q", rawImage))
- return
- }
- if _, isTagged := namedRef.(reference.Tagged); isTagged && query.AllTags {
- utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
- errors.Errorf("reference %q must not have a tag for all-tags", rawImage))
- return
- }
-
- authConf, authfile, err := auth.GetCredentials(r)
- if err != nil {
- utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
- return
- }
- defer auth.RemoveAuthfile(authfile)
-
- // Setup the registry options
- dockerRegistryOptions := image.DockerRegistryOptions{
- DockerRegistryCreds: authConf,
- OSChoice: query.OverrideOS,
- ArchitectureChoice: query.OverrideArch,
- VariantChoice: query.OverrideVariant,
- }
- if _, found := r.URL.Query()["tlsVerify"]; found {
- dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
- }
-
- sys := runtime.SystemContext()
- if sys == nil {
- sys = image.GetSystemContext("", authfile, false)
- }
- dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
- sys.DockerAuthConfig = authConf
-
- // Prepare the images we want to pull
- imagesToPull := []string{}
- res := []handlers.LibpodImagesPullReport{}
- imageName := namedRef.String()
-
- if !query.AllTags {
- imagesToPull = append(imagesToPull, imageName)
- } else {
- tags, err := docker.GetRepositoryTags(context.Background(), sys, imageRef)
- if err != nil {
- utils.InternalServerError(w, errors.Wrap(err, "error getting repository tags"))
- return
- }
- for _, tag := range tags {
- imagesToPull = append(imagesToPull, fmt.Sprintf("%s:%s", imageName, tag))
- }
- }
-
- // Finally pull the images
- for _, img := range imagesToPull {
- newImage, err := runtime.ImageRuntime().New(
- context.Background(),
- img,
- "",
- authfile,
- os.Stderr,
- &dockerRegistryOptions,
- image.SigningOptions{},
- nil,
- util.PullImageAlways)
- if err != nil {
- utils.InternalServerError(w, err)
- return
- }
- res = append(res, handlers.LibpodImagesPullReport{ID: newImage.ID()})
- }
-
- utils.WriteResponse(w, http.StatusOK, res)
-}
-
// PushImage is the handler for the compat http endpoint for pushing images.
func PushImage(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value("decoder").(*schema.Decoder)
diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go
new file mode 100644
index 000000000..8a2f4f4cf
--- /dev/null
+++ b/pkg/api/handlers/libpod/images_pull.go
@@ -0,0 +1,193 @@
+package libpod
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/containers/image/v5/docker"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/image"
+ "github.com/containers/podman/v2/pkg/api/handlers/utils"
+ "github.com/containers/podman/v2/pkg/auth"
+ "github.com/containers/podman/v2/pkg/channel"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/containers/podman/v2/pkg/util"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// ImagesPull is the v2 libpod endpoint for pulling images. Note that the
+// mandatory `reference` must be a reference to a registry (i.e., of docker
+// transport or be normalized to one). Other transports are rejected as they
+// do not make sense in a remote context.
+func ImagesPull(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Reference string `schema:"reference"`
+ OverrideOS string `schema:"overrideOS"`
+ OverrideArch string `schema:"overrideArch"`
+ OverrideVariant string `schema:"overrideVariant"`
+ TLSVerify bool `schema:"tlsVerify"`
+ AllTags bool `schema:"allTags"`
+ }{
+ TLSVerify: true,
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ if len(query.Reference) == 0 {
+ utils.InternalServerError(w, errors.New("reference parameter cannot be empty"))
+ return
+ }
+
+ imageRef, err := utils.ParseDockerReference(query.Reference)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "image destination %q is not a docker-transport reference", query.Reference))
+ return
+ }
+
+ // Trim the docker-transport prefix.
+ rawImage := strings.TrimPrefix(query.Reference, fmt.Sprintf("%s://", docker.Transport.Name()))
+
+ // all-tags doesn't work with a tagged reference, so let's check early
+ namedRef, err := reference.Parse(rawImage)
+ if err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "error parsing reference %q", rawImage))
+ return
+ }
+ if _, isTagged := namedRef.(reference.Tagged); isTagged && query.AllTags {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Errorf("reference %q must not have a tag for all-tags", rawImage))
+ return
+ }
+
+ authConf, authfile, err := auth.GetCredentials(r)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse %q header for %s", auth.XRegistryAuthHeader, r.URL.String()))
+ return
+ }
+ defer auth.RemoveAuthfile(authfile)
+
+ // Setup the registry options
+ dockerRegistryOptions := image.DockerRegistryOptions{
+ DockerRegistryCreds: authConf,
+ OSChoice: query.OverrideOS,
+ ArchitectureChoice: query.OverrideArch,
+ VariantChoice: query.OverrideVariant,
+ }
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ sys := runtime.SystemContext()
+ if sys == nil {
+ sys = image.GetSystemContext("", authfile, false)
+ }
+ dockerRegistryOptions.DockerCertPath = sys.DockerCertPath
+ sys.DockerAuthConfig = authConf
+
+ // Prepare the images we want to pull
+ imagesToPull := []string{}
+ imageName := namedRef.String()
+
+ if !query.AllTags {
+ imagesToPull = append(imagesToPull, imageName)
+ } else {
+ tags, err := docker.GetRepositoryTags(context.Background(), sys, imageRef)
+ if err != nil {
+ utils.InternalServerError(w, errors.Wrap(err, "error getting repository tags"))
+ return
+ }
+ for _, tag := range tags {
+ imagesToPull = append(imagesToPull, fmt.Sprintf("%s:%s", imageName, tag))
+ }
+ }
+
+ writer := channel.NewWriter(make(chan []byte, 1))
+ defer writer.Close()
+
+ stderr := channel.NewWriter(make(chan []byte, 1))
+ defer stderr.Close()
+
+ images := make([]string, 0, len(imagesToPull))
+ runCtx, cancel := context.WithCancel(context.Background())
+ go func(imgs []string) {
+ defer cancel()
+ // Finally pull the images
+ for _, img := range imgs {
+ newImage, err := runtime.ImageRuntime().New(
+ runCtx,
+ img,
+ "",
+ authfile,
+ writer,
+ &dockerRegistryOptions,
+ image.SigningOptions{},
+ nil,
+ util.PullImageAlways)
+ if err != nil {
+ stderr.Write([]byte(err.Error() + "\n"))
+ } else {
+ images = append(images, newImage.ID())
+ }
+ }
+ }(imagesToPull)
+
+ flush := func() {
+ if flusher, ok := w.(http.Flusher); ok {
+ flusher.Flush()
+ }
+ }
+
+ w.WriteHeader(http.StatusOK)
+ w.Header().Add("Content-Type", "application/json")
+ flush()
+
+ enc := json.NewEncoder(w)
+ enc.SetEscapeHTML(true)
+ var failed bool
+loop: // break out of for/select infinite loop
+ for {
+ var report entities.ImagePullReport
+ select {
+ case e := <-writer.Chan():
+ report.Stream = string(e)
+ if err := enc.Encode(report); err != nil {
+ stderr.Write([]byte(err.Error()))
+ }
+ flush()
+ case e := <-stderr.Chan():
+ failed = true
+ report.Error = string(e)
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+ flush()
+ case <-runCtx.Done():
+ if !failed {
+ report.Images = images
+ if err := enc.Encode(report); err != nil {
+ logrus.Warnf("Failed to json encode error %q", err.Error())
+ }
+ flush()
+ }
+ break loop // break out of for/select infinite loop
+ case <-r.Context().Done():
+ // Client has closed connection
+ break loop // break out of for/select infinite loop
+ }
+ }
+}
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index 05ab25d5b..596491044 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -270,51 +270,6 @@ func Import(ctx context.Context, changes []string, message, reference, u *string
return &report, response.Process(&report)
}
-// Pull is the binding for libpod's v2 endpoints for pulling images. Note that
-// `rawImage` must be a reference to a registry (i.e., of docker transport or be
-// normalized to one). Other transports are rejected as they do not make sense
-// in a remote context.
-func Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) ([]string, error) {
- conn, err := bindings.GetClient(ctx)
- if err != nil {
- return nil, err
- }
- params := url.Values{}
- params.Set("reference", rawImage)
- params.Set("overrideArch", options.OverrideArch)
- params.Set("overrideOS", options.OverrideOS)
- params.Set("overrideVariant", options.OverrideVariant)
- if options.SkipTLSVerify != types.OptionalBoolUndefined {
- // Note: we have to verify if skipped is false.
- verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
- params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
- }
- params.Set("allTags", strconv.FormatBool(options.AllTags))
-
- // TODO: have a global system context we can pass around (1st argument)
- header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
- if err != nil {
- return nil, err
- }
-
- response, err := conn.DoRequest(nil, http.MethodPost, "/images/pull", params, header)
- if err != nil {
- return nil, err
- }
-
- reports := []handlers.LibpodImagesPullReport{}
- if err := response.Process(&reports); err != nil {
- return nil, err
- }
-
- pulledImages := []string{}
- for _, r := range reports {
- pulledImages = append(pulledImages, r.ID)
- }
-
- return pulledImages, nil
-}
-
// Push is the binding for libpod's v2 endpoints for push images. Note that
// `source` must be a referring to an image in the remote's container storage.
// The destination must be a reference to a registry (i.e., of docker transport
diff --git a/pkg/bindings/images/pull.go b/pkg/bindings/images/pull.go
new file mode 100644
index 000000000..261a481a2
--- /dev/null
+++ b/pkg/bindings/images/pull.go
@@ -0,0 +1,98 @@
+package images
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
+ "strconv"
+
+ "github.com/containers/image/v5/types"
+ "github.com/containers/podman/v2/pkg/auth"
+ "github.com/containers/podman/v2/pkg/bindings"
+ "github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/hashicorp/go-multierror"
+)
+
+// Pull is the binding for libpod's v2 endpoints for pulling images. Note that
+// `rawImage` must be a reference to a registry (i.e., of docker transport or be
+// normalized to one). Other transports are rejected as they do not make sense
+// in a remote context. Progress reported on stderr
+func Pull(ctx context.Context, rawImage string, options entities.ImagePullOptions) ([]string, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("reference", rawImage)
+ params.Set("overrideArch", options.OverrideArch)
+ params.Set("overrideOS", options.OverrideOS)
+ params.Set("overrideVariant", options.OverrideVariant)
+
+ if options.SkipTLSVerify != types.OptionalBoolUndefined {
+ // Note: we have to verify if skipped is false.
+ verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse)
+ params.Set("tlsVerify", strconv.FormatBool(verifyTLS))
+ }
+ params.Set("allTags", strconv.FormatBool(options.AllTags))
+
+ // TODO: have a global system context we can pass around (1st argument)
+ header, err := auth.Header(nil, options.Authfile, options.Username, options.Password)
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := conn.DoRequest(nil, http.MethodPost, "/images/pull", params, header)
+ if err != nil {
+ return nil, err
+ }
+ defer response.Body.Close()
+
+ if !response.IsSuccess() {
+ return nil, response.Process(err)
+ }
+
+ // Historically pull writes status to stderr
+ stderr := io.Writer(os.Stderr)
+ if options.Quiet {
+ stderr = ioutil.Discard
+ }
+
+ dec := json.NewDecoder(response.Body)
+ var images []string
+ var mErr error
+ for {
+ var report entities.ImagePullReport
+ if err := dec.Decode(&report); err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+ report.Error = err.Error() + "\n"
+ }
+
+ select {
+ case <-response.Request.Context().Done():
+ return images, mErr
+ default:
+ // non-blocking select
+ }
+
+ switch {
+ case report.Stream != "":
+ fmt.Fprint(stderr, report.Stream)
+ case report.Error != "":
+ mErr = multierror.Append(mErr, errors.New(report.Error))
+ case len(report.Images) > 0:
+ images = report.Images
+ default:
+ return images, errors.New("failed to parse pull results stream, unexpected input")
+ }
+
+ }
+ return images, mErr
+}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 3a2e762d6..d0b738934 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -45,7 +45,7 @@ type Image struct {
HealthCheck *manifest.Schema2HealthConfig `json:",omitempty"`
}
-func (i *Image) Id() string { //nolint
+func (i *Image) Id() string { // nolint
return i.ID
}
@@ -70,7 +70,7 @@ type ImageSummary struct {
History []string `json:",omitempty"`
}
-func (i *ImageSummary) Id() string { //nolint
+func (i *ImageSummary) Id() string { // nolint
return i.ID
}
@@ -150,7 +150,12 @@ type ImagePullOptions struct {
// ImagePullReport is the response from pulling one or more images.
type ImagePullReport struct {
- Images []string
+ // Stream used to provide output from c/image
+ Stream string `json:"stream,omitempty"`
+ // Error contains text of errors from c/image
+ Error string `json:"error,omitempty"`
+ // Images contains the ID's of the images pulled
+ Images []string `json:"images,omitempty"`
}
// ImagePushOptions are the arguments for pushing images.
@@ -269,7 +274,7 @@ type ImageImportOptions struct {
}
type ImageImportReport struct {
- Id string //nolint
+ Id string // nolint
}
// ImageSaveOptions provide options for saving images.
@@ -349,7 +354,7 @@ type ImageUnmountOptions struct {
// ImageMountReport describes the response from image mount
type ImageMountReport struct {
Err error
- Id string //nolint
+ Id string // nolint
Name string
Repositories []string
Path string
@@ -358,5 +363,5 @@ type ImageMountReport struct {
// ImageUnmountReport describes the response from umounting an image
type ImageUnmountReport struct {
Err error
- Id string //nolint
+ Id string // nolint
}
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index 7ec84246d..3e47dc67a 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -23,33 +23,13 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
summaries := []*entities.ImageSummary{}
for _, img := range images {
- var repoTags []string
- if opts.All {
- pairs, err := libpodImage.ReposToMap(img.Names())
- if err != nil {
- return nil, err
- }
-
- for repo, tags := range pairs {
- for _, tag := range tags {
- repoTags = append(repoTags, repo+":"+tag)
- }
- }
- } else {
- repoTags, err = img.RepoTags()
- if err != nil {
- return nil, err
- }
- }
-
digests := make([]string, len(img.Digests()))
for j, d := range img.Digests() {
digests[j] = string(d)
}
e := entities.ImageSummary{
- ID: img.ID(),
-
+ ID: img.ID(),
ConfigDigest: string(img.ConfigDigest),
Created: img.Created().Unix(),
Dangling: img.Dangling(),
@@ -61,7 +41,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
ReadOnly: img.IsReadOnly(),
SharedSize: 0,
VirtualSize: img.VirtualSize,
- RepoTags: repoTags,
+ RepoTags: img.Names(), // may include tags and digests
}
e.Labels, _ = img.Labels(context.TODO())
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
index 6dfb52c63..659cc799c 100644
--- a/pkg/domain/infra/abi/play.go
+++ b/pkg/domain/infra/abi/play.go
@@ -132,6 +132,11 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
libpod.WithInfraContainer(),
libpod.WithPodName(podName),
}
+
+ if podYAML.ObjectMeta.Labels != nil {
+ podOptions = append(podOptions, libpod.WithPodLabels(podYAML.ObjectMeta.Labels))
+ }
+
// TODO we only configure Process namespace. We also need to account for Host{IPC,Network,PID}
// which is not currently possible with pod create
if podYAML.Spec.ShareProcessNamespace != nil && *podYAML.Spec.ShareProcessNamespace {
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index f9b8106ef..26c9c7e2e 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -227,23 +227,6 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
// TODO flag to set CNI plugins dir?
- // TODO I don't think these belong here?
- // Will follow up with a different PR to address
- //
- // Pod create options
-
- infraImageFlag := fs.Lookup("infra-image")
- if infraImageFlag != nil && infraImageFlag.Changed {
- infraImage, _ := fs.GetString("infra-image")
- options = append(options, libpod.WithDefaultInfraImage(infraImage))
- }
-
- infraCommandFlag := fs.Lookup("infra-command")
- if infraCommandFlag != nil && infraImageFlag.Changed {
- infraCommand, _ := fs.GetString("infra-command")
- options = append(options, libpod.WithDefaultInfraCommand(infraCommand))
- }
-
if !opts.withFDS {
options = append(options, libpod.WithEnableSDNotify())
}
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 0bd39d5a4..101201252 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -84,6 +84,15 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
if len(p.CNINetworks) > 0 {
options = append(options, libpod.WithPodNetworks(p.CNINetworks))
}
+
+ if len(p.InfraImage) > 0 {
+ options = append(options, libpod.WithInfraImage(p.InfraImage))
+ }
+
+ if len(p.InfraCommand) > 0 {
+ options = append(options, libpod.WithInfraCommand(p.InfraCommand))
+ }
+
switch p.NetNS.NSMode {
case specgen.Bridge, specgen.Default, "":
logrus.Debugf("Pod using default network mode")
diff --git a/pkg/specgen/pod_validate.go b/pkg/specgen/pod_validate.go
index d5e0aecf2..907c0bb69 100644
--- a/pkg/specgen/pod_validate.go
+++ b/pkg/specgen/pod_validate.go
@@ -95,12 +95,5 @@ func (p *PodSpecGenerator) Validate() error {
return exclusivePodOptions("NoManageHosts", "HostAdd")
}
- // Set Defaults
- if len(p.InfraImage) < 1 {
- p.InfraImage = containerConfig.Engine.InfraImage
- }
- if len(p.InfraCommand) < 1 {
- p.InfraCommand = []string{containerConfig.Engine.InfraCommand}
- }
return nil
}
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index a615a9f99..ddf2e20b8 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -241,6 +241,38 @@ WORKDIR /test
Expect(result.OutputToStringArray()).Should(HaveLen(0), "dangling image output: %q", result.OutputToString())
})
+ It("podman pull by digest and list --all", func() {
+ // Prevent regressing on issue #7651.
+ digestPullAndList := func(noneTag bool) {
+ session := podmanTest.Podman([]string{"pull", ALPINEAMD64DIGEST})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ result := podmanTest.Podman([]string{"images", "--all", ALPINEAMD64DIGEST})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+
+ found, _ := result.GrepString("<none>")
+ if noneTag {
+ Expect(found).To(BeTrue())
+ } else {
+ Expect(found).To(BeFalse())
+ }
+ }
+ // No "<none>" tag as tagged alpine instances should be present.
+ session := podmanTest.Podman([]string{"pull", ALPINELISTTAG})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ digestPullAndList(false)
+
+ // Now remove all images, re-pull by digest and check for the "<none>" tag.
+ session = podmanTest.Podman([]string{"rmi", "-af"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ digestPullAndList(true)
+ })
+
It("podman check for image with sha256: prefix", func() {
session := podmanTest.Podman([]string{"inspect", "--format=json", ALPINE})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 5e01971cb..87de92357 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -30,9 +30,14 @@ apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2019-07-17T14:44:08Z"
+ name: {{ .Name }}
labels:
app: {{ .Name }}
- name: {{ .Name }}
+{{ with .Labels }}
+ {{ range $key, $value := . }}
+ {{ $key }}: {{ $value }}
+ {{ end }}
+{{ end }}
{{ with .Annotations }}
annotations:
{{ range $key, $value := . }}
@@ -125,9 +130,14 @@ apiVersion: v1
kind: Deployment
metadata:
creationTimestamp: "2019-07-17T14:44:08Z"
+ name: {{ .Name }}
labels:
app: {{ .Name }}
- name: {{ .Name }}
+{{ with .Labels }}
+ {{ range $key, $value := . }}
+ {{ $key }}: {{ $value }}
+ {{ end }}
+{{ end }}
{{ with .Annotations }}
annotations:
{{ range $key, $value := . }}
@@ -145,6 +155,9 @@ spec:
metadata:
labels:
app: {{ .Name }}
+ {{- with .Labels }}{{ range $key, $value := . }}
+ {{ $key }}: {{ $value }}
+ {{- end }}{{ end }}
{{ with .Annotations }}
annotations:
{{ range $key, $value := . }}
@@ -266,6 +279,7 @@ type Pod struct {
HostAliases []HostAlias
Ctrs []*Ctr
Volumes []*Volume
+ Labels map[string]string
Annotations map[string]string
}
@@ -278,7 +292,15 @@ type HostAlias struct {
// and the configured options
// if no containers are added, it will add the default container
func getPod(options ...podOption) *Pod {
- p := Pod{defaultPodName, "", nil, make([]*Ctr, 0), make([]*Volume, 0), make(map[string]string)}
+ p := Pod{
+ Name: defaultPodName,
+ Hostname: "",
+ HostAliases: nil,
+ Ctrs: make([]*Ctr, 0),
+ Volumes: make([]*Volume, 0),
+ Labels: make(map[string]string),
+ Annotations: make(map[string]string),
+ }
for _, option := range options {
option(&p)
}
@@ -311,6 +333,12 @@ func withCtr(c *Ctr) podOption {
}
}
+func withLabel(k, v string) podOption {
+ return func(pod *Pod) {
+ pod.Labels[k] = v
+ }
+}
+
func withAnnotation(k, v string) podOption {
return func(pod *Pod) {
pod.Annotations[k] = v
@@ -327,12 +355,19 @@ func withVolume(v *Volume) podOption {
type Deployment struct {
Name string
Replicas int32
+ Labels map[string]string
Annotations map[string]string
PodTemplate *Pod
}
func getDeployment(options ...deploymentOption) *Deployment {
- d := Deployment{defaultDeploymentName, 1, make(map[string]string), getPod()}
+ d := Deployment{
+ Name: defaultDeploymentName,
+ Replicas: 1,
+ Labels: make(map[string]string),
+ Annotations: make(map[string]string),
+ PodTemplate: getPod(),
+ }
for _, option := range options {
option(&d)
}
@@ -342,6 +377,12 @@ func getDeployment(options ...deploymentOption) *Deployment {
type deploymentOption func(*Deployment)
+func withDeploymentLabel(k, v string) deploymentOption {
+ return func(deployment *Deployment) {
+ deployment.Labels[k] = v
+ }
+}
+
func withDeploymentAnnotation(k, v string) deploymentOption {
return func(deployment *Deployment) {
deployment.Annotations[k] = v
@@ -1077,4 +1118,29 @@ spec:
correct := fmt.Sprintf("%s:%s:%s", hostPathLocation, hostPathLocation, "ro")
Expect(inspect.OutputToString()).To(ContainSubstring(correct))
})
+
+ It("podman play kube applies labels to pods", func() {
+ SkipIfRemote()
+ var numReplicas int32 = 5
+ expectedLabelKey := "key1"
+ expectedLabelValue := "value1"
+ deployment := getDeployment(
+ withReplicas(numReplicas),
+ withPod(getPod(withLabel(expectedLabelKey, expectedLabelValue))),
+ )
+ err := generateDeploymentKubeYaml(deployment, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ correctLabels := expectedLabelKey + ":" + expectedLabelValue
+ for _, pod := range getPodNamesInDeployment(deployment) {
+ inspect := podmanTest.Podman([]string{"pod", "inspect", pod.Name, "--format", "'{{ .Labels }}'"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(Equal(0))
+ Expect(inspect.OutputToString()).To(ContainSubstring(correctLabels))
+ }
+ })
})
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index f260a123a..ed62e8a4b 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -329,4 +329,80 @@ var _ = Describe("Podman pod create", func() {
Expect(session.ExitCode()).To(Equal(0))
}
})
+
+ It("podman create pod with defaults", func() {
+ name := "test"
+ session := podmanTest.Podman([]string{"pod", "create", "--name", name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"pod", "inspect", name})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ data := check.InspectPodToJSON()
+
+ check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID})
+ check1.WaitWithDefaultTimeout()
+ Expect(check1.ExitCode()).To(Equal(0))
+ Expect(check1.OutputToString()).To(Equal("/pause"))
+ })
+
+ It("podman create pod with --infra-command", func() {
+ name := "test"
+ session := podmanTest.Podman([]string{"pod", "create", "--infra-command", "/pause1", "--name", name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"pod", "inspect", name})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ data := check.InspectPodToJSON()
+
+ check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID})
+ check1.WaitWithDefaultTimeout()
+ Expect(check1.ExitCode()).To(Equal(0))
+ Expect(check1.OutputToString()).To(Equal("/pause1"))
+ })
+
+ It("podman create pod with --infra-image", func() {
+ dockerfile := `FROM docker.io/library/alpine:latest
+entrypoint ["/fromimage"]
+`
+ podmanTest.BuildImage(dockerfile, "localhost/infra", "false")
+ name := "test"
+ session := podmanTest.Podman([]string{"pod", "create", "--infra-image", "localhost/infra", "--name", name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"pod", "inspect", name})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ data := check.InspectPodToJSON()
+
+ check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID})
+ check1.WaitWithDefaultTimeout()
+ Expect(check1.ExitCode()).To(Equal(0))
+ Expect(check1.OutputToString()).To(Equal("/fromimage"))
+ })
+
+ It("podman create pod with --infra-command --infra-image", func() {
+ dockerfile := `FROM docker.io/library/alpine:latest
+entrypoint ["/fromimage"]
+`
+ podmanTest.BuildImage(dockerfile, "localhost/infra", "false")
+ name := "test"
+ session := podmanTest.Podman([]string{"pod", "create", "--infra-image", "localhost/infra", "--infra-command", "/fromcommand", "--name", name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"pod", "inspect", name})
+ check.WaitWithDefaultTimeout()
+ Expect(check.ExitCode()).To(Equal(0))
+ data := check.InspectPodToJSON()
+
+ check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID})
+ check1.WaitWithDefaultTimeout()
+ Expect(check1.ExitCode()).To(Equal(0))
+ Expect(check1.OutputToString()).To(Equal("/fromcommand"))
+ })
})
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 9959c9efb..186a85883 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -701,7 +701,7 @@ gopkg.in/yaml.v3
# k8s.io/api v0.0.0-20190620084959-7cf5895f2711
k8s.io/api/apps/v1
k8s.io/api/core/v1
-# k8s.io/apimachinery v0.19.1
+# k8s.io/apimachinery v0.19.2
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/apis/meta/v1