container runlabel
Implement container runlabel for v2. Local client only. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
		
							parent
							
								
									7cd2e35203
								
							
						
					
					
						commit
						61828cf480
					
				| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
package containers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/common/pkg/auth"
 | 
			
		||||
	"github.com/containers/image/v5/types"
 | 
			
		||||
	"github.com/containers/libpod/cmd/podman/registry"
 | 
			
		||||
	"github.com/containers/libpod/pkg/domain/entities"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
	"github.com/spf13/cobra"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// runlabelOptionsWrapper allows for combining API-only with CLI-only options
 | 
			
		||||
// and to convert between them.
 | 
			
		||||
type runlabelOptionsWrapper struct {
 | 
			
		||||
	entities.ContainerRunlabelOptions
 | 
			
		||||
	TLSVerifyCLI bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	runlabelOptions     = runlabelOptionsWrapper{}
 | 
			
		||||
	runlabelDescription = "Executes a command as described by a container image label."
 | 
			
		||||
	runlabelCommand     = &cobra.Command{
 | 
			
		||||
		Use:   "runlabel [flags] LABEL IMAGE [ARG...]",
 | 
			
		||||
		Short: "Execute the command described by an image label",
 | 
			
		||||
		Long:  runlabelDescription,
 | 
			
		||||
		RunE:  runlabel,
 | 
			
		||||
		Args:  cobra.MinimumNArgs(2),
 | 
			
		||||
		Example: `podman container runlabel run imageID
 | 
			
		||||
  podman container runlabel --pull install imageID arg1 arg2
 | 
			
		||||
  podman container runlabel --display run myImage`,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	registry.Commands = append(registry.Commands, registry.CliCommand{
 | 
			
		||||
		Mode:    []entities.EngineMode{entities.ABIMode},
 | 
			
		||||
		Command: runlabelCommand,
 | 
			
		||||
		Parent:  containerCmd,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	flags := rmCommand.Flags()
 | 
			
		||||
	flags.StringVar(&runlabelOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
 | 
			
		||||
	flags.StringVar(&runlabelOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
 | 
			
		||||
	flags.StringVar(&runlabelOptions.Credentials, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
 | 
			
		||||
	flags.BoolVar(&runlabelOptions.Display, "display", false, "Preview the command that the label would run")
 | 
			
		||||
	flags.StringVarP(&runlabelOptions.Name, "name", "n", "", "Assign a name to the container")
 | 
			
		||||
	flags.StringVar(&runlabelOptions.Optional1, "opt1", "", "Optional parameter to pass for install")
 | 
			
		||||
	flags.StringVar(&runlabelOptions.Optional2, "opt2", "", "Optional parameter to pass for install")
 | 
			
		||||
	flags.StringVar(&runlabelOptions.Optional3, "opt3", "", "Optional parameter to pass for install")
 | 
			
		||||
	flags.BoolP("pull", "p", false, "Pull the image if it does not exist locally prior to executing the label contents")
 | 
			
		||||
	flags.BoolVarP(&runlabelOptions.Quiet, "quiet", "q", false, "Suppress output information when installing images")
 | 
			
		||||
	flags.BoolVar(&runlabelOptions.Replace, "replace", false, "Replace existing container with a new one from the image")
 | 
			
		||||
	flags.StringVar(&runlabelOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
 | 
			
		||||
	flags.BoolVar(&runlabelOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
 | 
			
		||||
 | 
			
		||||
	// Hide the optional flags.
 | 
			
		||||
	_ = flags.MarkHidden("opt1")
 | 
			
		||||
	_ = flags.MarkHidden("opt2")
 | 
			
		||||
	_ = flags.MarkHidden("opt3")
 | 
			
		||||
 | 
			
		||||
	if err := flags.MarkDeprecated("pull", "podman will pull if not found in local storage"); err != nil {
 | 
			
		||||
		logrus.Error("unable to mark pull flag deprecated")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runlabel(cmd *cobra.Command, args []string) error {
 | 
			
		||||
	if cmd.Flags().Changed("tls-verify") {
 | 
			
		||||
		runlabelOptions.SkipTLSVerify = types.NewOptionalBool(!runlabelOptions.TLSVerifyCLI)
 | 
			
		||||
	}
 | 
			
		||||
	if runlabelOptions.Authfile != "" {
 | 
			
		||||
		if _, err := os.Stat(runlabelOptions.Authfile); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "error getting authfile %s", runlabelOptions.Authfile)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return registry.ContainerEngine().ContainerRunlabel(context.Background(), args[0], args[1], args[2:], runlabelOptions.ContainerRunlabelOptions)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -6,11 +6,49 @@ import (
 | 
			
		|||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/image/v5/types"
 | 
			
		||||
	"github.com/containers/libpod/libpod/define"
 | 
			
		||||
	"github.com/containers/libpod/pkg/specgen"
 | 
			
		||||
	"github.com/cri-o/ocicni/pkg/ocicni"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ContainerRunlabelOptions are the options to execute container-runlabel.
 | 
			
		||||
type ContainerRunlabelOptions struct {
 | 
			
		||||
	// Authfile - path to an authentication file.
 | 
			
		||||
	Authfile string
 | 
			
		||||
	// CertDir - path to a directory containing TLS certifications and
 | 
			
		||||
	// keys.
 | 
			
		||||
	CertDir string
 | 
			
		||||
	// Credentials - `user:password` to use when pulling an image.
 | 
			
		||||
	Credentials string
 | 
			
		||||
	// Display - do not execute but print the command.
 | 
			
		||||
	Display bool
 | 
			
		||||
	// Replace - replace an existing container with a new one from the
 | 
			
		||||
	// image.
 | 
			
		||||
	Replace bool
 | 
			
		||||
	// Name - use this name when executing the runlabel container.
 | 
			
		||||
	Name string
 | 
			
		||||
	// Optional1 - fist optional parameter for install.
 | 
			
		||||
	Optional1 string
 | 
			
		||||
	// Optional2 - second optional parameter for install.
 | 
			
		||||
	Optional2 string
 | 
			
		||||
	// Optional3 - third optional parameter for install.
 | 
			
		||||
	Optional3 string
 | 
			
		||||
	// Pull - pull the specified image if it's not in the local storage.
 | 
			
		||||
	Pull bool
 | 
			
		||||
	// Quiet - suppress output when pulling images.
 | 
			
		||||
	Quiet bool
 | 
			
		||||
	// SignaturePolicy - path to a signature-policy file.
 | 
			
		||||
	SignaturePolicy string
 | 
			
		||||
	// SkipTLSVerify - skip HTTPS and certificate verifications when
 | 
			
		||||
	// contacting registries.
 | 
			
		||||
	SkipTLSVerify types.OptionalBool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainerRunlabelReport contains the results from executing container-runlabel.
 | 
			
		||||
type ContainerRunlabelReport struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WaitOptions struct {
 | 
			
		||||
	Condition define.ContainerStatus
 | 
			
		||||
	Interval  time.Duration
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ type ContainerEngine interface {
 | 
			
		|||
	ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
 | 
			
		||||
	ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
 | 
			
		||||
	ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
 | 
			
		||||
	ContainerRunlabel(ctx context.Context, label string, image string, args []string, opts ContainerRunlabelOptions) error
 | 
			
		||||
	ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
 | 
			
		||||
	ContainerStats(ctx context.Context, namesOrIds []string, options ContainerStatsOptions) error
 | 
			
		||||
	ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,280 @@
 | 
			
		|||
package abi
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/image/v5/types"
 | 
			
		||||
	"github.com/containers/libpod/libpod/define"
 | 
			
		||||
	"github.com/containers/libpod/libpod/image"
 | 
			
		||||
	"github.com/containers/libpod/pkg/domain/entities"
 | 
			
		||||
	envLib "github.com/containers/libpod/pkg/env"
 | 
			
		||||
	"github.com/containers/libpod/pkg/util"
 | 
			
		||||
	"github.com/containers/libpod/utils"
 | 
			
		||||
	"github.com/google/shlex"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string, imageRef string, args []string, options entities.ContainerRunlabelOptions) error {
 | 
			
		||||
	// First, get the image and pull it if needed.
 | 
			
		||||
	img, err := ic.runlabelImage(ctx, label, imageRef, options)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	// Extract the runlabel from the image.
 | 
			
		||||
	runlabel, err := img.GetLabel(ctx, label)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd, env, err := generateRunlabelCommand(runlabel, img, args, options)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stdErr := os.Stderr
 | 
			
		||||
	stdOut := os.Stdout
 | 
			
		||||
	stdIn := os.Stdin
 | 
			
		||||
	if options.Quiet {
 | 
			
		||||
		stdErr = nil
 | 
			
		||||
		stdOut = nil
 | 
			
		||||
		stdIn = nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If container already exists && --replace given -- Nuke it
 | 
			
		||||
	if options.Replace {
 | 
			
		||||
		for i, entry := range cmd {
 | 
			
		||||
			if entry == "--name" {
 | 
			
		||||
				name := cmd[i+1]
 | 
			
		||||
				ctr, err := ic.Libpod.LookupContainer(name)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					if errors.Cause(err) != define.ErrNoSuchCtr {
 | 
			
		||||
						logrus.Debugf("Error occurred searching for container %s: %s", name, err.Error())
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					logrus.Debugf("Runlabel --replace option given. Container %s will be deleted. The new container will be named %s", ctr.ID(), name)
 | 
			
		||||
					if err := ic.Libpod.RemoveContainer(ctx, ctr, true, false); err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// runlabelImage returns an image based on the specified image AND options.
 | 
			
		||||
func (ic *ContainerEngine) runlabelImage(ctx context.Context, label string, imageRef string, options entities.ContainerRunlabelOptions) (*image.Image, error) {
 | 
			
		||||
	// First, look up the image locally. If we get an error and requested
 | 
			
		||||
	// to pull, fallthrough and pull it.
 | 
			
		||||
	img, err := ic.Libpod.ImageRuntime().NewFromLocal(imageRef)
 | 
			
		||||
	switch {
 | 
			
		||||
	case err == nil:
 | 
			
		||||
		return img, nil
 | 
			
		||||
	case !options.Pull:
 | 
			
		||||
		return nil, err
 | 
			
		||||
	default:
 | 
			
		||||
		// Fallthrough and pull!
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Parse credentials if specified.
 | 
			
		||||
	var credentials *types.DockerAuthConfig
 | 
			
		||||
	if options.Credentials != "" {
 | 
			
		||||
		credentials, err = util.ParseRegistryCreds(options.Credentials)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Suppress pull progress bars if requested.
 | 
			
		||||
	pullOutput := os.Stdout
 | 
			
		||||
	if options.Quiet {
 | 
			
		||||
		pullOutput = nil // c/image/copy takes care of the rest
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Pull the image.
 | 
			
		||||
	dockerRegistryOptions := image.DockerRegistryOptions{
 | 
			
		||||
		DockerCertPath:              options.CertDir,
 | 
			
		||||
		DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
 | 
			
		||||
		DockerRegistryCreds:         credentials,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ic.Libpod.ImageRuntime().New(ctx, imageRef, options.SignaturePolicy, options.Authfile, pullOutput, &dockerRegistryOptions, image.SigningOptions{}, &label, util.PullImageMissing)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateRunlabelCommand generates the to-be-executed command as a string
 | 
			
		||||
// slice along with a base environment.
 | 
			
		||||
func generateRunlabelCommand(runlabel string, img *image.Image, args []string, options entities.ContainerRunlabelOptions) ([]string, []string, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		err             error
 | 
			
		||||
		name, imageName string
 | 
			
		||||
		globalOpts      string
 | 
			
		||||
		cmd, env        []string
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// TODO: How do we get global opts as done in v1?
 | 
			
		||||
 | 
			
		||||
	// Extract the imageName (or ID).
 | 
			
		||||
	imgNames := img.Names()
 | 
			
		||||
	if len(imgNames) == 0 {
 | 
			
		||||
		imageName = img.ID()
 | 
			
		||||
	} else {
 | 
			
		||||
		imageName = imgNames[0]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Use the user-specified name or extract one from the image.
 | 
			
		||||
	if options.Name != "" {
 | 
			
		||||
		name = options.Name
 | 
			
		||||
	} else {
 | 
			
		||||
		name, err = image.GetImageBaseName(imageName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Append the user-specified arguments to the runlabel (command).
 | 
			
		||||
	if len(args) > 0 {
 | 
			
		||||
		runlabel = fmt.Sprintf("%s %s", runlabel, strings.Join(args, " "))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd, err = generateCommand(runlabel, imageName, name, globalOpts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	env = generateRunEnvironment(name, imageName, options)
 | 
			
		||||
	env = append(env, "PODMAN_RUNLABEL_NESTED=1")
 | 
			
		||||
	envmap, err := envLib.ParseSlice(env)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	envmapper := func(k string) string {
 | 
			
		||||
		switch k {
 | 
			
		||||
		case "OPT1":
 | 
			
		||||
			return envmap["OPT1"]
 | 
			
		||||
		case "OPT2":
 | 
			
		||||
			return envmap["OPT2"]
 | 
			
		||||
		case "OPT3":
 | 
			
		||||
			return envmap["OPT3"]
 | 
			
		||||
		case "PWD":
 | 
			
		||||
			// I would prefer to use os.getenv but it appears PWD is not in the os env list.
 | 
			
		||||
			d, err := os.Getwd()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				logrus.Error("unable to determine current working directory")
 | 
			
		||||
				return ""
 | 
			
		||||
			}
 | 
			
		||||
			return d
 | 
			
		||||
		}
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	newS := os.Expand(strings.Join(cmd, " "), envmapper)
 | 
			
		||||
	cmd, err = shlex.Split(newS)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return cmd, env, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateCommand takes a label (string) and converts it to an executable command
 | 
			
		||||
func generateCommand(command, imageName, name, globalOpts string) ([]string, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		newCommand []string
 | 
			
		||||
	)
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		name = imageName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd, err := shlex.Split(command)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	prog, err := substituteCommand(cmd[0])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	newCommand = append(newCommand, prog)
 | 
			
		||||
 | 
			
		||||
	for _, arg := range cmd[1:] {
 | 
			
		||||
		var newArg string
 | 
			
		||||
		switch arg {
 | 
			
		||||
		case "IMAGE":
 | 
			
		||||
			newArg = imageName
 | 
			
		||||
		case "$IMAGE":
 | 
			
		||||
			newArg = imageName
 | 
			
		||||
		case "IMAGE=IMAGE":
 | 
			
		||||
			newArg = fmt.Sprintf("IMAGE=%s", imageName)
 | 
			
		||||
		case "IMAGE=$IMAGE":
 | 
			
		||||
			newArg = fmt.Sprintf("IMAGE=%s", imageName)
 | 
			
		||||
		case "NAME":
 | 
			
		||||
			newArg = name
 | 
			
		||||
		case "NAME=NAME":
 | 
			
		||||
			newArg = fmt.Sprintf("NAME=%s", name)
 | 
			
		||||
		case "NAME=$NAME":
 | 
			
		||||
			newArg = fmt.Sprintf("NAME=%s", name)
 | 
			
		||||
		case "$NAME":
 | 
			
		||||
			newArg = name
 | 
			
		||||
		case "$GLOBAL_OPTS":
 | 
			
		||||
			newArg = globalOpts
 | 
			
		||||
		default:
 | 
			
		||||
			newArg = arg
 | 
			
		||||
		}
 | 
			
		||||
		newCommand = append(newCommand, newArg)
 | 
			
		||||
	}
 | 
			
		||||
	return newCommand, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GenerateRunEnvironment merges the current environment variables with optional
 | 
			
		||||
// environment variables provided by the user
 | 
			
		||||
func generateRunEnvironment(name, imageName string, options entities.ContainerRunlabelOptions) []string {
 | 
			
		||||
	newEnv := os.Environ()
 | 
			
		||||
	if options.Optional1 != "" {
 | 
			
		||||
		newEnv = append(newEnv, fmt.Sprintf("OPT1=%s", options.Optional1))
 | 
			
		||||
	}
 | 
			
		||||
	if options.Optional2 != "" {
 | 
			
		||||
		newEnv = append(newEnv, fmt.Sprintf("OPT2=%s", options.Optional2))
 | 
			
		||||
	}
 | 
			
		||||
	if options.Optional3 != "" {
 | 
			
		||||
		newEnv = append(newEnv, fmt.Sprintf("OPT3=%s", options.Optional3))
 | 
			
		||||
	}
 | 
			
		||||
	return newEnv
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func substituteCommand(cmd string) (string, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		newCommand string
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// Replace cmd with "/proc/self/exe" if "podman" or "docker" is being
 | 
			
		||||
	// used. If "/usr/bin/docker" is provided, we also sub in podman.
 | 
			
		||||
	// Otherwise, leave the command unchanged.
 | 
			
		||||
	if cmd == "podman" || filepath.Base(cmd) == "docker" {
 | 
			
		||||
		newCommand = "/proc/self/exe"
 | 
			
		||||
	} else {
 | 
			
		||||
		newCommand = cmd
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If cmd is an absolute or relative path, check if the file exists.
 | 
			
		||||
	// Throw an error if it doesn't exist.
 | 
			
		||||
	if strings.Contains(newCommand, "/") || strings.HasPrefix(newCommand, ".") {
 | 
			
		||||
		res, err := filepath.Abs(newCommand)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := os.Stat(res); !os.IsNotExist(err) {
 | 
			
		||||
			return res, nil
 | 
			
		||||
		} else if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newCommand, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,10 @@ import (
 | 
			
		|||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string, image string, args []string, options entities.ContainerRunlabelOptions) error {
 | 
			
		||||
	return errors.New("not implemented")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
 | 
			
		||||
	exists, err := containers.Exists(ic.ClientCxt, nameOrId)
 | 
			
		||||
	return &entities.BoolReport{Value: exists}, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,7 +31,6 @@ var _ = Describe("podman container runlabel", func() {
 | 
			
		|||
	)
 | 
			
		||||
 | 
			
		||||
	BeforeEach(func() {
 | 
			
		||||
		Skip(v2fail)
 | 
			
		||||
		tempdir, err = CreateTempDirInTempDir()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			os.Exit(1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue