diff options
-rw-r--r-- | cmd/podman/create.go | 2 | ||||
-rw-r--r-- | cmd/podman/play_kube.go | 2 | ||||
-rw-r--r-- | cmd/podman/pull.go | 2 | ||||
-rw-r--r-- | cmd/podman/runlabel.go | 2 | ||||
-rw-r--r-- | cmd/podman/shared/container.go | 2 | ||||
-rw-r--r-- | cmd/podman/sign.go | 2 | ||||
-rw-r--r-- | contrib/perftest/main.go | 2 | ||||
-rw-r--r-- | docs/podman-container-runlabel.1.md | 3 | ||||
-rw-r--r-- | libpod/adapter/runtime.go | 4 | ||||
-rw-r--r-- | libpod/adapter/runtime_remote.go | 6 | ||||
-rw-r--r-- | libpod/image/image.go | 4 | ||||
-rw-r--r-- | libpod/image/image_test.go | 8 | ||||
-rw-r--r-- | libpod/image/pull.go | 44 | ||||
-rw-r--r-- | libpod/runtime_pod_infra_linux.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/containers_create.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/images.go | 8 | ||||
-rw-r--r-- | test/e2e/runlabel_test.go | 11 |
17 files changed, 78 insertions, 28 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go index c56efa153..2d85abd35 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -134,7 +134,7 @@ func createContainer(c *cli.Context, runtime *libpod.Runtime) (*libpod.Container writer = os.Stderr } - newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false) + newImage, err := runtime.ImageRuntime().New(ctx, c.Args()[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false, nil) if err != nil { return nil, nil, err } diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index 2ce2e21bb..4753dd0a6 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -146,7 +146,7 @@ func playKubeYAMLCmd(c *cli.Context) error { } for _, container := range podYAML.Spec.Containers { - newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.String("signature-policy"), c.String("authfile"), writer, &dockerRegistryOptions, image2.SigningOptions{}, false) + newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.String("signature-policy"), c.String("authfile"), writer, &dockerRegistryOptions, image2.SigningOptions{}, false, nil) if err != nil { return err } diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index 2a78d0c54..f70e5cded 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -123,7 +123,7 @@ func pullCmd(c *cli.Context) error { imgID = newImage[0].ID() } else { authfile := getAuthFile(c.String("authfile")) - newImage, err := runtime.New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true) + newImage, err := runtime.New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true, nil) if err != nil { return errors.Wrapf(err, "error pulling image %q", image) } diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go index 48a296260..b16a93fd9 100644 --- a/cmd/podman/runlabel.go +++ b/cmd/podman/runlabel.go @@ -166,7 +166,7 @@ func runlabelCmd(c *cli.Context) error { return err } if runLabel == "" { - return nil + return errors.Errorf("%s does not have a label of %s", runlabelImage, label) } cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, c.String("name"), opts, extraArgs) diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index 9040c4a5c..f84fb8261 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -609,7 +609,7 @@ func GetRunlabel(label string, runlabelImage string, ctx context.Context, runtim registryCreds = creds } dockerRegistryOptions.DockerRegistryCreds = registryCreds - newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false) + newImage, err = runtime.ImageRuntime().New(ctx, runlabelImage, signaturePolicyPath, authfile, output, &dockerRegistryOptions, image.SigningOptions{}, false, &label) } else { newImage, err = runtime.ImageRuntime().NewFromLocal(runlabelImage) } diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go index 1d9aecdc9..22aa07230 100644 --- a/cmd/podman/sign.go +++ b/cmd/podman/sign.go @@ -104,7 +104,7 @@ func signCmd(c *cli.Context) error { } // create the signstore file - newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false) + newImage, err := runtime.ImageRuntime().New(getContext(), signimage, runtime.GetConfig().SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{SignBy: signby}, false, nil) if err != nil { return errors.Wrapf(err, "error pulling image %s", signimage) } diff --git a/contrib/perftest/main.go b/contrib/perftest/main.go index 0d0947890..6a6725ab9 100644 --- a/contrib/perftest/main.go +++ b/contrib/perftest/main.go @@ -103,7 +103,7 @@ func main() { } fmt.Printf("image %s not found locally, fetching from remote registry..\n", *testImageName) - testImage, err = client.ImageRuntime().New(ctx, *testImageName, "", "", writer, &dockerRegistryOptions, image2.SigningOptions{}, false) + testImage, err = client.ImageRuntime().New(ctx, *testImageName, "", "", writer, &dockerRegistryOptions, image2.SigningOptions{}, false, nil) if err != nil { logrus.Fatal(err) } diff --git a/docs/podman-container-runlabel.1.md b/docs/podman-container-runlabel.1.md index 6f7b4dae8..c5d7a278f 100644 --- a/docs/podman-container-runlabel.1.md +++ b/docs/podman-container-runlabel.1.md @@ -26,6 +26,9 @@ If the container image has a LABEL INSTALL instruction like the following: `podman container runlabel` will set the following environment variables for use in the command: +If the container image does not have the desired label, an error message will be displayed along with a non-zero +return code. + Note: Podman will always ensure that `podman` is the first argument of the command being executed. **LABEL** diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go index f4961437e..007257714 100644 --- a/libpod/adapter/runtime.go +++ b/libpod/adapter/runtime.go @@ -78,8 +78,8 @@ func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef type } // New calls into local storage to look for an image in local storage or to pull it -func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) { - img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull) +func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) { + img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull, label) if err != nil { return nil, err } diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go index f184ce0a9..0633c036d 100644 --- a/libpod/adapter/runtime_remote.go +++ b/libpod/adapter/runtime_remote.go @@ -6,6 +6,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/pkg/errors" "io" "strings" "time" @@ -156,7 +157,10 @@ func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef type } // New calls into local storage to look for an image in local storage or to pull it -func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) { +func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) { + if label != nil { + return nil, errors.New("the remote client function does not support checking a remote image for a label") + } // TODO Creds needs to be figured out here too, like above tlsBool := dockeroptions.DockerInsecureSkipTLSVerify // Remember SkipTlsVerify is the opposite of tlsverify diff --git a/libpod/image/image.go b/libpod/image/image.go index ea326d820..c871eb3e4 100644 --- a/libpod/image/image.go +++ b/libpod/image/image.go @@ -125,7 +125,7 @@ func (ir *Runtime) NewFromLocal(name string) (*Image, error) { // New creates a new image object where the image could be local // or remote -func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, forcePull bool) (*Image, error) { +func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *DockerRegistryOptions, signingoptions SigningOptions, forcePull bool, label *string) (*Image, error) { // We don't know if the image is local or not ... check local first newImage := Image{ InputName: name, @@ -145,7 +145,7 @@ func (ir *Runtime) New(ctx context.Context, name, signaturePolicyPath, authfile if signaturePolicyPath == "" { signaturePolicyPath = ir.SignaturePolicyPath } - imageName, err := ir.pullImageFromHeuristicSource(ctx, name, writer, authfile, signaturePolicyPath, signingoptions, dockeroptions) + imageName, err := ir.pullImageFromHeuristicSource(ctx, name, writer, authfile, signaturePolicyPath, signingoptions, dockeroptions, label) if err != nil { return nil, errors.Wrapf(err, "unable to pull %s", name) } diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go index 077ae460e..075ba119d 100644 --- a/libpod/image/image_test.go +++ b/libpod/image/image_test.go @@ -87,9 +87,9 @@ func TestImage_NewFromLocal(t *testing.T) { // Need images to be present for this test ir, err := NewImageRuntimeFromOptions(so) assert.NoError(t, err) - bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, false) + bb, err := ir.New(context.Background(), "docker.io/library/busybox:latest", "", "", writer, nil, SigningOptions{}, false, nil) assert.NoError(t, err) - bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, false) + bbglibc, err := ir.New(context.Background(), "docker.io/library/busybox:glibc", "", "", writer, nil, SigningOptions{}, false, nil) assert.NoError(t, err) tm, err := makeLocalMatrix(bb, bbglibc) @@ -136,7 +136,7 @@ func TestImage_New(t *testing.T) { // Iterate over the names and delete the image // after the pull for _, img := range names { - newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, false) + newImage, err := ir.New(context.Background(), img, "", "", writer, nil, SigningOptions{}, false, nil) assert.NoError(t, err) assert.NotEqual(t, newImage.ID(), "") err = newImage.Remove(false) @@ -164,7 +164,7 @@ func TestImage_MatchRepoTag(t *testing.T) { } ir, err := NewImageRuntimeFromOptions(so) assert.NoError(t, err) - newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, false) + newImage, err := ir.New(context.Background(), "busybox", "", "", os.Stdout, nil, SigningOptions{}, false, nil) assert.NoError(t, err) err = newImage.TagImage("foo:latest") assert.NoError(t, err) diff --git a/libpod/image/pull.go b/libpod/image/pull.go index 434b83520..6fef96e37 100644 --- a/libpod/image/pull.go +++ b/libpod/image/pull.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "strings" cp "github.com/containers/image/copy" "github.com/containers/image/directory" @@ -192,7 +193,7 @@ func (ir *Runtime) pullGoalFromImageReference(ctx context.Context, srcRef types. // pullImageFromHeuristicSource pulls an image based on inputName, which is heuristically parsed and may involve configured registries. // Use pullImageFromReference if the source is known precisely. -func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) ([]string, error) { +func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName string, writer io.Writer, authfile, signaturePolicyPath string, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, label *string) ([]string, error) { var goal *pullGoal sc := GetSystemContext(signaturePolicyPath, authfile, false) srcRef, err := alltransports.ParseImageName(inputName) @@ -208,7 +209,7 @@ func (ir *Runtime) pullImageFromHeuristicSource(ctx context.Context, inputName s return nil, errors.Wrapf(err, "error determining pull goal for image %q", inputName) } } - return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions) + return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, label) } // pullImageFromReference pulls an image from a types.imageReference. @@ -218,11 +219,11 @@ func (ir *Runtime) pullImageFromReference(ctx context.Context, srcRef types.Imag if err != nil { return nil, errors.Wrapf(err, "error determining pull goal for image %q", transports.ImageName(srcRef)) } - return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions) + return ir.doPullImage(ctx, sc, *goal, writer, signingOptions, dockerOptions, nil) } // doPullImage is an internal helper interpreting pullGoal. Almost everyone should call one of the callers of doPullImage instead. -func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions) ([]string, error) { +func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goal pullGoal, writer io.Writer, signingOptions SigningOptions, dockerOptions *DockerRegistryOptions, label *string) ([]string, error) { policyContext, err := getPolicyContext(sc) if err != nil { return nil, err @@ -230,8 +231,12 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa defer policyContext.Destroy() systemRegistriesConfPath := registries.SystemRegistriesConfPath() - var images []string - var pullErrors *multierror.Error + + var ( + images []string + pullErrors *multierror.Error + ) + for _, imageInfo := range goal.refPairs { copyOptions := getCopyOptions(sc, writer, dockerOptions, nil, signingOptions, "", nil) copyOptions.SourceCtx.SystemRegistriesConfPath = systemRegistriesConfPath // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place. @@ -239,6 +244,13 @@ func (ir *Runtime) doPullImage(ctx context.Context, sc *types.SystemContext, goa if writer != nil && (imageInfo.srcRef.Transport().Name() == DockerTransport || imageInfo.srcRef.Transport().Name() == AtomicTransport) { io.WriteString(writer, fmt.Sprintf("Trying to pull %s...", imageInfo.image)) } + // If the label is not nil, check if the label exists and if not, return err + if label != nil { + if err := checkRemoteImageForLabel(ctx, *label, imageInfo, sc); err != nil { + return nil, err + } + } + _, err = cp.Image(ctx, policyContext, imageInfo.dstRef, imageInfo.srcRef, copyOptions) if err != nil { pullErrors = multierror.Append(pullErrors, err) @@ -314,3 +326,23 @@ func (ir *Runtime) pullGoalFromPossiblyUnqualifiedName(inputName string) (*pullG searchedRegistries: searchRegistries, }, nil } + +// checkRemoteImageForLabel checks if the remote image has a specific label. if the label exists, we +// return nil, else we return an error +func checkRemoteImageForLabel(ctx context.Context, label string, imageInfo pullRefPair, sc *types.SystemContext) error { + labelImage, err := imageInfo.srcRef.NewImage(ctx, sc) + if err != nil { + return err + } + remoteInspect, err := labelImage.Inspect(ctx) + if err != nil { + return err + } + // Labels are case insensitive; so we iterate instead of simple lookup + for k := range remoteInspect.Labels { + if strings.ToLower(label) == strings.ToLower(k) { + return nil + } + } + return errors.Errorf("%s has no label %s", imageInfo.image, label) +} diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 5e1051150..4f221764a 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -67,7 +67,7 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container, return nil, ErrRuntimeStopped } - newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, false) + newImage, err := r.ImageRuntime().New(ctx, r.config.InfraImage, "", "", nil, nil, image.SigningOptions{}, false, nil) if err != nil { return nil, err } diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go index d72eaeb18..cc707b11f 100644 --- a/pkg/varlinkapi/containers_create.go +++ b/pkg/varlinkapi/containers_create.go @@ -25,7 +25,7 @@ func (i *LibpodAPI) CreateContainer(call iopodman.VarlinkCall, config iopodman.C rtc := i.Runtime.GetConfig() ctx := getContext() - newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false) + newImage, err := i.Runtime.ImageRuntime().New(ctx, config.Image, rtc.SignaturePolicyPath, "", os.Stderr, nil, image.SigningOptions{}, false, nil) if err != nil { return call.ReplyErrorOccurred(err.Error()) } diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go index d6a9b7301..0ab645802 100644 --- a/pkg/varlinkapi/images.go +++ b/pkg/varlinkapi/images.go @@ -573,7 +573,7 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, c } imageID = newImage[0].ID() } else { - newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false) + newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false, nil) if err != nil { return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error())) } @@ -610,15 +610,15 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman. runLabel, imageName, err := shared.GetRunlabel(input.Label, input.Image, ctx, i.Runtime, input.Pull, input.Creds, dockerRegistryOptions, input.Authfile, input.SignaturePolicyPath, nil) if err != nil { - return err + return call.ReplyErrorOccurred(err.Error()) } if runLabel == "" { - return nil + return call.ReplyErrorOccurred(fmt.Sprintf("%s does not contain the label %s", input.Image, input.Label)) } cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, input.Name, input.Opts, input.ExtraArgs) if err != nil { - return err + return call.ReplyErrorOccurred(err.Error()) } if err := utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...); err != nil { return call.ReplyErrorOccurred(err.Error()) diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go index 9b4f584b0..49b9e13d8 100644 --- a/test/e2e/runlabel_test.go +++ b/test/e2e/runlabel_test.go @@ -68,4 +68,15 @@ var _ = Describe("podman container runlabel", func() { result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) }) + It("podman container runlabel bogus label should result in non-zero exit code", func() { + result := podmanTest.Podman([]string{"container", "runlabel", "RUN", ALPINE}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).ToNot(Equal(0)) + }) + It("podman container runlabel bogus label in remote image should result in non-zero exit", func() { + result := podmanTest.Podman([]string{"container", "runlabel", "RUN", "docker.io/library/ubuntu:latest"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).ToNot(Equal(0)) + + }) }) |