Changes to container runlabel for toolbox project

The toolbox project would benefit from a few changes to more closely
resembe the original atomic cli project.  Changes made are:

* only pull image for container runlabel if the label exists in the image
* if a container image does not have the desired label, exit with non-zero

Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
baude
2019-01-11 10:33:25 -06:00
parent b71088a01e
commit 735f0de633
17 changed files with 78 additions and 28 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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**

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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
}

View File

@ -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())
}

View File

@ -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())

View File

@ -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))
})
})