diff options
Diffstat (limited to 'pkg/adapter')
-rw-r--r-- | pkg/adapter/autoupdate.go | 11 | ||||
-rw-r--r-- | pkg/adapter/autoupdate_remote.go | 11 | ||||
-rw-r--r-- | pkg/adapter/checkpoint_restore.go | 2 | ||||
-rw-r--r-- | pkg/adapter/containers.go | 125 | ||||
-rw-r--r-- | pkg/adapter/containers_remote.go | 19 | ||||
-rw-r--r-- | pkg/adapter/images.go | 33 | ||||
-rw-r--r-- | pkg/adapter/images_remote.go | 31 | ||||
-rw-r--r-- | pkg/adapter/network.go | 6 | ||||
-rw-r--r-- | pkg/adapter/pods.go | 196 | ||||
-rw-r--r-- | pkg/adapter/pods_remote.go | 13 | ||||
-rw-r--r-- | pkg/adapter/runtime.go | 54 | ||||
-rw-r--r-- | pkg/adapter/runtime_remote.go | 69 | ||||
-rw-r--r-- | pkg/adapter/sigproxy_linux.go | 13 | ||||
-rw-r--r-- | pkg/adapter/terminal.go | 6 | ||||
-rw-r--r-- | pkg/adapter/terminal_linux.go | 14 | ||||
-rw-r--r-- | pkg/adapter/terminal_unsupported.go | 23 |
16 files changed, 431 insertions, 195 deletions
diff --git a/pkg/adapter/autoupdate.go b/pkg/adapter/autoupdate.go new file mode 100644 index 000000000..01f7a29c5 --- /dev/null +++ b/pkg/adapter/autoupdate.go @@ -0,0 +1,11 @@ +// +build !remoteclient + +package adapter + +import ( + "github.com/containers/libpod/pkg/autoupdate" +) + +func (r *LocalRuntime) AutoUpdate() ([]string, []error) { + return autoupdate.AutoUpdate(r.Runtime) +} diff --git a/pkg/adapter/autoupdate_remote.go b/pkg/adapter/autoupdate_remote.go new file mode 100644 index 000000000..a2a82d0d4 --- /dev/null +++ b/pkg/adapter/autoupdate_remote.go @@ -0,0 +1,11 @@ +// +build remoteclient + +package adapter + +import ( + "github.com/containers/libpod/libpod/define" +) + +func (r *LocalRuntime) AutoUpdate() ([]string, []error) { + return nil, []error{define.ErrNotImplemented} +} diff --git a/pkg/adapter/checkpoint_restore.go b/pkg/adapter/checkpoint_restore.go index 7f80b782a..a5b74013b 100644 --- a/pkg/adapter/checkpoint_restore.go +++ b/pkg/adapter/checkpoint_restore.go @@ -114,7 +114,7 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri return nil, err } - _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing) + _, err = runtime.ImageRuntime().New(ctx, config.RootfsImageName, rtc.Engine.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, nil, util.PullImageMissing) if err != nil { return nil, err } diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index f66999ffa..a2f73307b 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -16,17 +16,18 @@ import ( "time" "github.com/containers/buildah" + cfg "github.com/containers/common/pkg/config" "github.com/containers/image/v5/manifest" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/cmd/podman/shared/parse" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/libpod/logs" "github.com/containers/libpod/pkg/adapter/shortcuts" - "github.com/containers/libpod/pkg/systemdgen" + envLib "github.com/containers/libpod/pkg/env" + "github.com/containers/libpod/pkg/systemd/generate" "github.com/containers/storage" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -338,7 +339,11 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *logs.LogOptions) er if tailLen < 0 { tailLen = 0 } - logChannel := make(chan *logs.LogLine, tailLen*len(c.InputArgs)+1) + numContainers := len(c.InputArgs) + if numContainers == 0 { + numContainers = 1 + } + logChannel := make(chan *logs.LogLine, tailLen*numContainers+1) containers, err := shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime) if err != nil { return err @@ -376,11 +381,11 @@ func (r *LocalRuntime) selectDetachKeys(flagValue string) (string, error) { if err != nil { return "", errors.Wrapf(err, "unable to retrieve runtime config") } - if config.DetachKeys != "" { - return config.DetachKeys, nil + if config.Engine.DetachKeys != "" { + return config.Engine.DetachKeys, nil } - return define.DefaultDetachKeys, nil + return cfg.DefaultDetachKeys, nil } // Run a libpod container @@ -444,9 +449,12 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode } } - keys, err := r.selectDetachKeys(c.String("detach-keys")) - if err != nil { - return exitCode, err + keys := c.String("detach-keys") + if !c.IsSet("detach-keys") { + keys, err = r.selectDetachKeys(keys) + if err != nil { + return exitCode, err + } } // if the container was created as part of a pod, also start its dependencies, if any. @@ -462,6 +470,10 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID()) } } + if errors.Cause(err) == define.ErrWillDeadlock { + logrus.Debugf("Deadlock error: %v", err) + return define.ExitCode(err), errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID()) + } return define.ExitCode(err), err } @@ -534,9 +546,12 @@ func (r *LocalRuntime) Attach(ctx context.Context, c *cliconfig.AttachValues) er inputStream = nil } - keys, err := r.selectDetachKeys(c.DetachKeys) - if err != nil { - return err + keys := c.DetachKeys + if !c.IsSet("detach-keys") { + keys, err = r.selectDetachKeys(keys) + if err != nil { + return err + } } // If the container is in a pod, also set to recursively start dependencies @@ -674,9 +689,12 @@ func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigP } } - keys, err := r.selectDetachKeys(c.DetachKeys) - if err != nil { - return exitCode, err + keys := c.DetachKeys + if !c.IsSet("detach-keys") { + keys, err = r.selectDetachKeys(keys) + if err != nil { + return exitCode, err + } } // attach to the container and also start it not already running @@ -689,6 +707,11 @@ func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigP return exitCode, nil } + if errors.Cause(err) == define.ErrWillDeadlock { + logrus.Debugf("Deadlock error: %v", err) + return define.ExitCode(err), errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID()) + } + if ctrRunning { return 0, err } @@ -722,6 +745,10 @@ func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigP if lastError != nil { fmt.Fprintln(os.Stderr, lastError) } + if errors.Cause(err) == define.ErrWillDeadlock { + lastError = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks") + continue + } lastError = errors.Wrapf(err, "unable to start container %q", container) continue } @@ -961,9 +988,20 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal // Validate given environment variables env := map[string]string{} - if err := parse.ReadKVStrings(env, cli.EnvFile, cli.Env); err != nil { - return ec, errors.Wrapf(err, "unable to process environment variables") + if len(cli.EnvFile) > 0 { + for _, f := range cli.EnvFile { + fileEnv, err := envLib.ParseFile(f) + if err != nil { + return ec, err + } + env = envLib.Join(env, fileEnv) + } + } + cliEnv, err := envLib.ParseSlice(cli.Env) + if err != nil { + return ec, errors.Wrap(err, "error parsing environment variables") } + env = envLib.Join(env, cliEnv) streams := new(libpod.AttachStreams) streams.OutputStream = os.Stdout @@ -975,9 +1013,12 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal streams.AttachOutput = true streams.AttachError = true - keys, err := r.selectDetachKeys(cli.DetachKeys) - if err != nil { - return ec, err + keys := cli.DetachKeys + if !cli.IsSet("detach-keys") { + keys, err = r.selectDetachKeys(keys) + if err != nil { + return ec, err + } } ec, err = ExecAttachCtr(ctx, ctr.Container, cli.Tty, cli.Privileged, env, cmd, cli.User, cli.Workdir, streams, uint(cli.PreserveFDs), keys) @@ -1017,7 +1058,8 @@ func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, filters []stri if c.PodID() != "" { return false } - if state == define.ContainerStateStopped || state == define.ContainerStateExited { + if state == define.ContainerStateStopped || state == define.ContainerStateExited || + state == define.ContainerStateCreated || state == define.ContainerStateConfigured { return true } return false @@ -1072,6 +1114,15 @@ func (r *LocalRuntime) CleanupContainers(ctx context.Context, cli *cliconfig.Cle } else { failures[ctr.ID()] = err } + + if cli.RemoveImage { + _, imageName := ctr.Image() + if err := removeContainerImage(ctx, ctr, r); err != nil { + failures[imageName] = err + } else { + ok = append(ok, imageName) + } + } } return ok, failures, nil } @@ -1091,6 +1142,16 @@ func cleanupContainer(ctx context.Context, ctr *libpod.Container, runtime *Local return nil } +func removeContainerImage(ctx context.Context, ctr *libpod.Container, runtime *LocalRuntime) error { + _, imageName := ctr.Image() + ctrImage, err := runtime.NewImageFromLocal(imageName) + if err != nil { + return err + } + _, err = runtime.RemoveImage(ctx, ctrImage, false) + return err +} + // Port displays port information about existing containers func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) { var ( @@ -1100,7 +1161,11 @@ func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) { ) if !c.All { - containers, err = shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime) + names := []string{} + if len(c.InputArgs) >= 1 { + names = []string{c.InputArgs[0]} + } + containers, err = shortcuts.GetContainersByContext(false, c.Latest, names, r.Runtime) } else { containers, err = r.Runtime.GetRunningContainers() } @@ -1142,7 +1207,7 @@ func generateServiceName(c *cliconfig.GenerateSystemdValues, ctr *libpod.Contain // generateSystemdgenContainerInfo is a helper to generate a // systemdgen.ContainerInfo for `GenerateSystemd`. -func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSystemdValues, nameOrID string, pod *libpod.Pod) (*systemdgen.ContainerInfo, bool, error) { +func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSystemdValues, nameOrID string, pod *libpod.Pod) (*generate.ContainerInfo, bool, error) { ctr, err := r.Runtime.LookupContainer(nameOrID) if err != nil { return nil, false, err @@ -1160,7 +1225,7 @@ func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSyst } name, serviceName := generateServiceName(c, ctr, pod) - info := &systemdgen.ContainerInfo{ + info := &generate.ContainerInfo{ ServiceName: serviceName, ContainerName: name, RestartPolicy: c.RestartPolicy, @@ -1175,7 +1240,7 @@ func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSyst // GenerateSystemd creates a unit file for a container or pod. func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) { - opts := systemdgen.Options{ + opts := generate.Options{ Files: c.Files, New: c.New, } @@ -1184,7 +1249,7 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri if info, found, err := r.generateSystemdgenContainerInfo(c, c.InputArgs[0], nil); found && err != nil { return "", err } else if found && err == nil { - return systemdgen.CreateContainerSystemdUnit(info, opts) + return generate.CreateContainerSystemdUnit(info, opts) } // --new does not support pods. @@ -1230,7 +1295,7 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri // Traverse the dependency graph and create systemdgen.ContainerInfo's for // each container. - containerInfos := []*systemdgen.ContainerInfo{podInfo} + containerInfos := []*generate.ContainerInfo{podInfo} for ctr, dependencies := range graph.DependencyMap() { // Skip the infra container as we already generated it. if ctr.ID() == infraID { @@ -1260,7 +1325,7 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri if i > 0 { builder.WriteByte('\n') } - out, err := systemdgen.CreateContainerSystemdUnit(info, opts) + out, err := generate.CreateContainerSystemdUnit(info, opts) if err != nil { return "", err } @@ -1305,9 +1370,9 @@ func (r *LocalRuntime) Commit(ctx context.Context, c *cliconfig.CommitValues, co return "", err } - sc := image.GetSystemContext(rtc.SignaturePolicyPath, "", false) + sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false) coptions := buildah.CommitOptions{ - SignaturePolicyPath: rtc.SignaturePolicyPath, + SignaturePolicyPath: rtc.Engine.SignaturePolicyPath, ReportWriter: writer, SystemContext: sc, PreferredManifestType: mimeType, diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 60ee3cb2d..46db7ebe8 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -15,11 +15,11 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/cmd/podman/shared/parse" iopodman "github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/logs" + envLib "github.com/containers/libpod/pkg/env" "github.com/containers/libpod/pkg/varlinkapi/virtwriter" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/docker/docker/pkg/term" @@ -32,12 +32,12 @@ import ( ) // Inspect returns an inspect struct from varlink -func (c *Container) Inspect(size bool) (*libpod.InspectContainerData, error) { +func (c *Container) Inspect(size bool) (*define.InspectContainerData, error) { reply, err := iopodman.ContainerInspectData().Call(c.Runtime.Conn, c.ID(), size) if err != nil { return nil, err } - data := libpod.InspectContainerData{} + data := define.InspectContainerData{} if err := json.Unmarshal([]byte(reply), &data); err != nil { return nil, err } @@ -1025,16 +1025,11 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal ) // default invalid command exit code // Validate given environment variables - env := map[string]string{} - if err := parse.ReadKVStrings(env, []string{}, cli.Env); err != nil { - return -1, errors.Wrapf(err, "Exec unable to process environment variables") - } - - // Build env slice of key=value strings for Exec - envs := []string{} - for k, v := range env { - envs = append(envs, fmt.Sprintf("%s=%s", k, v)) + cliEnv, err := envLib.ParseSlice(cli.Env) + if err != nil { + return 0, errors.Wrap(err, "error parsing environment variables") } + envs := envLib.Slice(cliEnv) resize := make(chan remotecommand.TerminalSize, 5) haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) diff --git a/pkg/adapter/images.go b/pkg/adapter/images.go deleted file mode 100644 index 762f1a656..000000000 --- a/pkg/adapter/images.go +++ /dev/null @@ -1,33 +0,0 @@ -// +build !remoteclient - -package adapter - -import ( - "github.com/containers/libpod/libpod/image" - "github.com/pkg/errors" -) - -// Tree ... -func (r *LocalRuntime) Tree(imageOrID string) (*image.InfoImage, map[string]*image.LayerInfo, *ContainerImage, error) { - img, err := r.NewImageFromLocal(imageOrID) - if err != nil { - return nil, nil, nil, err - } - - // Fetch map of image-layers, which is used for printing output. - layerInfoMap, err := image.GetLayersMapWithImageInfo(r.Runtime.ImageRuntime()) - if err != nil { - return nil, nil, nil, errors.Wrapf(err, "error while retrieving layers of image %q", img.InputName) - } - - // Create an imageInfo and fill the image and layer info - imageInfo := &image.InfoImage{ - ID: img.ID(), - Tags: img.Names(), - } - - if err := image.BuildImageHierarchyMap(imageInfo, layerInfoMap, img.TopLayer()); err != nil { - return nil, nil, nil, err - } - return imageInfo, layerInfoMap, img, nil -} diff --git a/pkg/adapter/images_remote.go b/pkg/adapter/images_remote.go index 1d4997d9a..e7b38dccc 100644 --- a/pkg/adapter/images_remote.go +++ b/pkg/adapter/images_remote.go @@ -7,9 +7,7 @@ import ( "encoding/json" iopodman "github.com/containers/libpod/cmd/podman/varlink" - "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/inspect" - "github.com/pkg/errors" ) // Inspect returns returns an ImageData struct from over a varlink connection @@ -24,32 +22,3 @@ func (i *ContainerImage) Inspect(ctx context.Context) (*inspect.ImageData, error } return &data, nil } - -// Tree ... -func (r *LocalRuntime) Tree(imageOrID string) (*image.InfoImage, map[string]*image.LayerInfo, *ContainerImage, error) { - layerInfoMap := make(map[string]*image.LayerInfo) - imageInfo := &image.InfoImage{} - - img, err := r.NewImageFromLocal(imageOrID) - if err != nil { - return nil, nil, nil, err - } - - reply, err := iopodman.GetLayersMapWithImageInfo().Call(r.Conn) - if err != nil { - return nil, nil, nil, errors.Wrap(err, "failed to obtain image layers") - } - if err := json.Unmarshal([]byte(reply), &layerInfoMap); err != nil { - return nil, nil, nil, errors.Wrap(err, "failed to unmarshal image layers") - } - - reply, err = iopodman.BuildImageHierarchyMap().Call(r.Conn, imageOrID) - if err != nil { - return nil, nil, nil, errors.Wrap(err, "failed to get build image map") - } - if err := json.Unmarshal([]byte(reply), imageInfo); err != nil { - return nil, nil, nil, errors.Wrap(err, "failed to unmarshal build image map") - } - - return imageInfo, layerInfoMap, img, nil -} diff --git a/pkg/adapter/network.go b/pkg/adapter/network.go index b25f54a13..577ffe19f 100644 --- a/pkg/adapter/network.go +++ b/pkg/adapter/network.go @@ -23,9 +23,9 @@ func getCNIConfDir(r *LocalRuntime) (string, error) { if err != nil { return "", err } - configPath := config.CNIConfigDir + configPath := config.Network.NetworkConfigDir - if len(config.CNIConfigDir) < 1 { + if len(config.Network.NetworkConfigDir) < 1 { configPath = network.CNIConfigDir } return configPath, nil @@ -211,7 +211,7 @@ func (r *LocalRuntime) NetworkCreateBridge(cli *cliconfig.NetworkCreateValues) ( plugins = append(plugins, network.NewPortMapPlugin()) plugins = append(plugins, network.NewFirewallPlugin()) // if we find the dnsname plugin, we add configuration for it - if network.HasDNSNamePlugin(runtimeConfig.CNIPluginDir) && !cli.DisableDNS { + if network.HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) && !cli.DisableDNS { // Note: in the future we might like to allow for dynamic domain names plugins = append(plugins, network.NewDNSNamePlugin(network.DefaultPodmanDomainName)) } diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 5891c361f..102eabd8b 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -7,11 +7,13 @@ import ( "fmt" "io" "io/ioutil" + "net" "os" "path/filepath" "strings" "github.com/containers/buildah/pkg/parse" + "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" @@ -20,6 +22,7 @@ import ( "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/adapter/shortcuts" ann "github.com/containers/libpod/pkg/annotations" + envLib "github.com/containers/libpod/pkg/env" ns "github.com/containers/libpod/pkg/namespaces" createconfig "github.com/containers/libpod/pkg/spec" "github.com/containers/libpod/pkg/util" @@ -58,9 +61,9 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal } logrus.Debugf("Setting maximum rm workers to %d", maxWorkers) - states := []string{shared.PodStateStopped, shared.PodStateExited} + states := []string{define.PodStateStopped, define.PodStateExited} if cli.Force { - states = append(states, shared.PodStateRunning) + states = append(states, define.PodStateRunning) } pods, err := r.GetPodsByStatus(states) @@ -119,19 +122,31 @@ func (r *LocalRuntime) GetLatestPod() (*Pod, error) { return &pod, err } +// GetPodsWithFilters gets the filtered list of pods based on the filter parameters provided. +func (r *LocalRuntime) GetPodsWithFilters(filters string) ([]*Pod, error) { + pods, err := shared.GetPodsWithFilters(r.Runtime, filters) + if err != nil { + return nil, err + } + return r.podstoAdapterPods(pods) +} + +func (r *LocalRuntime) podstoAdapterPods(pod []*libpod.Pod) ([]*Pod, error) { + var pods []*Pod + for _, i := range pod { + + pods = append(pods, &Pod{i}) + } + return pods, nil +} + // GetAllPods gets all pods and wraps it in an adapter pod func (r *LocalRuntime) GetAllPods() ([]*Pod, error) { - var pods []*Pod allPods, err := r.Runtime.GetAllPods() if err != nil { return nil, err } - for _, p := range allPods { - pod := Pod{} - pod.Pod = p - pods = append(pods, &pod) - } - return pods, nil + return r.podstoAdapterPods(allPods) } // LookupPod gets a pod by name or id and wraps it in an adapter pod @@ -247,6 +262,17 @@ func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateVa err error ) + // This needs to be first, as a lot of options depend on + // WithInfraContainer() + if cli.Infra { + options = append(options, libpod.WithInfraContainer()) + nsOptions, err := shared.GetNamespaceOptions(strings.Split(cli.Share, ",")) + if err != nil { + return "", err + } + options = append(options, nsOptions...) + } + if cli.Flag("cgroup-parent").Changed { options = append(options, libpod.WithPodCgroupParent(cli.CgroupParent)) } @@ -263,17 +289,78 @@ func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateVa options = append(options, libpod.WithPodHostname(cli.Hostname)) } - if cli.Infra { - options = append(options, libpod.WithInfraContainer()) - nsOptions, err := shared.GetNamespaceOptions(strings.Split(cli.Share, ",")) + if cli.Flag("add-host").Changed { + options = append(options, libpod.WithPodHosts(cli.StringSlice("add-host"))) + } + if cli.Flag("dns").Changed { + dns := cli.StringSlice("dns") + foundHost := false + for _, entry := range dns { + if entry == "host" { + foundHost = true + } + } + if foundHost && len(dns) > 1 { + return "", errors.Errorf("cannot set dns=host and still provide other DNS servers") + } + if foundHost { + options = append(options, libpod.WithPodUseImageResolvConf()) + } else { + options = append(options, libpod.WithPodDNS(cli.StringSlice("dns"))) + } + } + if cli.Flag("dns-opt").Changed { + options = append(options, libpod.WithPodDNSOption(cli.StringSlice("dns-opt"))) + } + if cli.Flag("dns-search").Changed { + options = append(options, libpod.WithPodDNSSearch(cli.StringSlice("dns-search"))) + } + if cli.Flag("ip").Changed { + ip := net.ParseIP(cli.String("ip")) + if ip == nil { + return "", errors.Errorf("invalid IP address %q passed to --ip", cli.String("ip")) + } + + options = append(options, libpod.WithPodStaticIP(ip)) + } + if cli.Flag("mac-address").Changed { + mac, err := net.ParseMAC(cli.String("mac-address")) if err != nil { - return "", err + return "", errors.Wrapf(err, "invalid MAC address %q passed to --mac-address", cli.String("mac-address")) + } + + options = append(options, libpod.WithPodStaticMAC(mac)) + } + if cli.Flag("network").Changed { + netValue := cli.String("network") + switch strings.ToLower(netValue) { + case "bridge": + // Do nothing. + // TODO: Maybe this should be split between slirp and + // bridge? Better to wait until someone asks... + logrus.Debugf("Pod using default network mode") + case "host": + logrus.Debugf("Pod will use host networking") + options = append(options, libpod.WithPodHostNetwork()) + case "": + return "", errors.Errorf("invalid value passed to --net: must provide a comma-separated list of CNI networks or host") + default: + // We'll assume this is a comma-separated list of CNI + // networks. + networks := strings.Split(netValue, ",") + logrus.Debugf("Pod joining CNI networks: %v", networks) + options = append(options, libpod.WithPodNetworks(networks)) + } + } + if cli.Flag("no-hosts").Changed { + if cli.Bool("no-hosts") { + options = append(options, libpod.WithPodUseImageHosts()) } - options = append(options, nsOptions...) } - if len(cli.Publish) > 0 { - portBindings, err := shared.CreatePortBindings(cli.Publish) + publish := cli.StringSlice("publish") + if len(publish) > 0 { + portBindings, err := shared.CreatePortBindings(publish) if err != nil { return "", err } @@ -496,6 +583,10 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa } podOptions = append(podOptions, libpod.WithPodHostname(hostname)) + if podYAML.Spec.HostNetwork { + podOptions = append(podOptions, libpod.WithPodHostNetwork()) + } + nsOptions, err := shared.GetNamespaceOptions(strings.Split(shared.DefaultKernelNamespaces, ",")) if err != nil { return nil, err @@ -564,8 +655,8 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa return nil, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path) } } - // unconditionally label a newly created volume as private - if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil { + // Label a newly created volume + if err := libpod.LabelVolumePath(hostPath.Path); err != nil { return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path) } case v1.HostPathFileOrCreate: @@ -578,8 +669,8 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa logrus.Warnf("Error in closing newly created HostPath file: %v", err) } } - // unconditionally label a newly created volume as private - if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil { + // unconditionally label a newly created volume + if err := libpod.LabelVolumePath(hostPath.Path); err != nil { return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path) } case v1.HostPathDirectory: @@ -604,7 +695,24 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa } for _, container := range podYAML.Spec.Containers { - newImage, err := r.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageMissing) + pullPolicy := util.PullImageMissing + if len(container.ImagePullPolicy) > 0 { + pullPolicy, err = util.ValidatePullType(string(container.ImagePullPolicy)) + if err != nil { + return nil, err + } + } + named, err := reference.ParseNormalizedNamed(container.Image) + if err != nil { + return nil, err + } + // In kube, if the image is tagged with latest, it should always pull + if tagged, isTagged := named.(reference.NamedTagged); isTagged { + if tagged.Tag() == image.LatestTag { + pullPolicy = util.PullImageAlways + } + } + newImage, err := r.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy) if err != nil { return nil, err } @@ -660,6 +768,12 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping { var infraPorts []ocicni.PortMapping for _, container := range containers { for _, p := range container.Ports { + if p.HostPort != 0 && p.ContainerPort == 0 { + p.ContainerPort = p.HostPort + } + if p.Protocol == "" { + p.Protocol = "tcp" + } portBinding := ocicni.PortMapping{ HostPort: p.HostPort, ContainerPort: p.ContainerPort, @@ -668,7 +782,12 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping { if p.HostIP != "" { logrus.Debug("HostIP on port bindings is not supported") } - infraPorts = append(infraPorts, portBinding) + // only hostPort is utilized in podman context, all container ports + // are accessible inside the shared network namespace + if p.HostPort != 0 { + infraPorts = append(infraPorts, portBinding) + } + } } return infraPorts @@ -746,7 +865,6 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container containerConfig.ImageID = newImage.ID() containerConfig.Name = containerYAML.Name containerConfig.Tty = containerYAML.TTY - containerConfig.WorkDir = containerYAML.WorkingDir containerConfig.Pod = podID @@ -778,6 +896,27 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container containerConfig.StopSignal = 15 + containerConfig.WorkDir = "/" + if imageData != nil { + // FIXME, + // we are currently ignoring imageData.Config.ExposedPorts + containerConfig.BuiltinImgVolumes = imageData.Config.Volumes + if imageData.Config.WorkingDir != "" { + containerConfig.WorkDir = imageData.Config.WorkingDir + } + containerConfig.Labels = imageData.Config.Labels + if imageData.Config.StopSignal != "" { + stopSignal, err := util.ParseSignal(imageData.Config.StopSignal) + if err != nil { + return nil, err + } + containerConfig.StopSignal = stopSignal + } + } + + if containerYAML.WorkingDir != "" { + containerConfig.WorkDir = containerYAML.WorkingDir + } // If the user does not pass in ID mappings, just set to basics if userConfig.IDMappings == nil { userConfig.IDMappings = &storage.IDMappingOptions{} @@ -801,9 +940,6 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container containerConfig.User = userConfig containerConfig.Security = securityConfig - // Set default environment variables and incorporate data from image, if necessary - envs := shared.EnvVariablesFromData(imageData) - annotations := make(map[string]string) if infraID != "" { annotations[ann.SandboxID] = infraID @@ -812,6 +948,14 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container containerConfig.Annotations = annotations // Environment Variables + envs := map[string]string{} + if imageData != nil { + imageEnv, err := envLib.ParseSlice(imageData.Config.Env) + if err != nil { + return nil, errors.Wrap(err, "error parsing image environment variables") + } + envs = imageEnv + } for _, e := range containerYAML.Env { envs[e.Name] = e.Value } diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go index 16d34769e..6b8f22f15 100644 --- a/pkg/adapter/pods_remote.go +++ b/pkg/adapter/pods_remote.go @@ -10,7 +10,7 @@ import ( "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" - "github.com/containers/libpod/cmd/podman/varlink" + iopodman "github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/varlinkapi" @@ -185,7 +185,7 @@ func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateVa Infra: cli.Infra, InfraCommand: cli.InfraCommand, InfraImage: cli.InfraCommand, - Publish: cli.Publish, + Publish: cli.StringSlice("publish"), } return iopodman.CreatePod().Call(r.Conn, pc) @@ -208,6 +208,11 @@ func (r *LocalRuntime) GetAllPods() ([]*Pod, error) { return pods, nil } +// This is a empty implementation stating remoteclient not yet implemented +func (r *LocalRuntime) GetPodsWithFilters(filters string) ([]*Pod, error) { + return nil, define.ErrNotImplemented +} + // GetPodsByStatus returns a slice of pods filtered by a libpod status func (r *LocalRuntime) GetPodsByStatus(statuses []string) ([]*Pod, error) { podIDs, err := iopodman.GetPodsByStatus().Call(r.Conn, statuses) @@ -540,9 +545,9 @@ func (r *LocalRuntime) PrunePods(ctx context.Context, cli *cliconfig.PodPruneVal ok = []string{} failures = map[string]error{} ) - states := []string{shared.PodStateStopped, shared.PodStateExited} + states := []string{define.PodStateStopped, define.PodStateExited} if cli.Force { - states = append(states, shared.PodStateRunning) + states = append(states, define.PodStateRunning) } ids, err := iopodman.GetPodsByStatus().Call(r.Conn, states) diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 40089797d..7a181e7e5 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -13,7 +13,6 @@ import ( "github.com/containers/buildah" "github.com/containers/buildah/imagebuildah" "github.com/containers/buildah/pkg/formats" - "github.com/containers/buildah/pkg/parse" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/types" "github.com/containers/libpod/cmd/podman/cliconfig" @@ -133,6 +132,15 @@ func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { return &ContainerImage{img}, nil } +// ImageTree reutnrs an new image.Tree for the provided `imageOrID` and `whatrequires` flag +func (r *LocalRuntime) ImageTree(imageOrID string, whatRequires bool) (string, error) { + img, err := r.Runtime.ImageRuntime().NewFromLocal(imageOrID) + if err != nil { + return "", err + } + return img.GenerateTree(whatRequires) +} + // LoadFromArchiveReference calls into local storage to load an image from an archive func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) { var containerImages []*ContainerImage @@ -287,37 +295,13 @@ func libpodVolumeToVolume(volumes []*libpod.Volume) []*Volume { // Build is the wrapper to build images func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, options imagebuildah.BuildOptions, dockerfiles []string) (string, reference.Canonical, error) { - namespaceOptions, networkPolicy, err := parse.NamespaceOptions(c.PodmanCommand.Command) - if err != nil { - return "", nil, errors.Wrapf(err, "error parsing namespace-related options") - } - usernsOption, idmappingOptions, err := parse.IDMappingOptions(c.PodmanCommand.Command, options.Isolation) - if err != nil { - return "", nil, errors.Wrapf(err, "error parsing ID mapping options") - } - namespaceOptions.AddOrReplace(usernsOption...) - - systemContext, err := parse.SystemContextFromOptions(c.PodmanCommand.Command) - if err != nil { - return "", nil, errors.Wrapf(err, "error building system context") - } authfile := c.Authfile if len(c.Authfile) == 0 { authfile = os.Getenv("REGISTRY_AUTH_FILE") } - systemContext.AuthFilePath = authfile - commonOpts, err := parse.CommonBuildOptions(c.PodmanCommand.Command) - if err != nil { - return "", nil, err - } - - options.NamespaceOptions = namespaceOptions - options.ConfigureNetwork = networkPolicy - options.IDMappingOptions = idmappingOptions - options.CommonBuildOpts = commonOpts - options.SystemContext = systemContext + options.SystemContext.AuthFilePath = authfile if c.GlobalFlags.Runtime != "" { options.Runtime = c.GlobalFlags.Runtime @@ -338,7 +322,23 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti // PruneVolumes is a wrapper function for libpod PruneVolumes func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) { - return r.Runtime.PruneVolumes(ctx) + var ( + vids []string + errs []error + ) + reports, err := r.Runtime.PruneVolumes(ctx) + if err != nil { + errs = append(errs, err) + return vids, errs + } + for k, v := range reports { + if v == nil { + vids = append(vids, k) + } else { + errs = append(errs, v) + } + } + return vids, errs } // SaveImage is a wrapper function for saving an image to the local filesystem diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index c908358ff..a616e6c7a 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -17,6 +17,7 @@ import ( "github.com/containers/buildah/imagebuildah" "github.com/containers/buildah/pkg/formats" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/types" "github.com/containers/libpod/cmd/podman/cliconfig" @@ -113,15 +114,20 @@ func (r RemoteRuntime) DeferredShutdown(force bool) { } } -// RuntimeConfig is a bogus wrapper for compat with the libpod runtime -type RuntimeConfig struct { +// Containers is a bogus wrapper for compat with the libpod runtime +type ContainersConfig struct { // CGroupManager is the CGroup Manager to use // Valid values are "cgroupfs" and "systemd" CgroupManager string } +// RuntimeConfig is a bogus wrapper for compat with the libpod runtime +type RuntimeConfig struct { + Containers ContainersConfig +} + // Shutdown is a bogus wrapper for compat with the libpod runtime -func (r *RemoteRuntime) GetConfig() (*RuntimeConfig, error) { +func (r *RemoteRuntime) GetConfig() (*config.Config, error) { return nil, nil } @@ -201,8 +207,11 @@ func (r *LocalRuntime) GetRWImages() ([]*ContainerImage, error) { } func (r *LocalRuntime) GetFilteredImages(filters []string, rwOnly bool) ([]*ContainerImage, error) { + if len(filters) > 0 { + return nil, errors.Wrap(define.ErrNotImplemented, "filtering images is not supported on the remote client") + } var newImages []*ContainerImage - images, err := iopodman.ListImagesWithFilters().Call(r.Conn, filters) + images, err := iopodman.ListImages().Call(r.Conn) if err != nil { return nil, err } @@ -288,7 +297,8 @@ func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) { // LoadFromArchiveReference creates an image from a local archive func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) { var iid string - reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, srcRef.DockerReference().String()) + creds := iopodman.AuthConfig{} + reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, srcRef.DockerReference().String(), creds) if err != nil { return nil, err } @@ -320,7 +330,12 @@ func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authf if label != nil { return nil, errors.New("the remote client function does not support checking a remote image for a label") } - reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, name) + creds := iopodman.AuthConfig{} + if dockeroptions.DockerRegistryCreds != nil { + creds.Username = dockeroptions.DockerRegistryCreds.Username + creds.Password = dockeroptions.DockerRegistryCreds.Password + } + reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, name, creds) if err != nil { return nil, err } @@ -344,6 +359,10 @@ func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authf return newImage, nil } +func (r *LocalRuntime) ImageTree(imageOrID string, whatRequires bool) (string, error) { + return iopodman.ImageTree().Call(r.Conn, imageOrID, whatRequires) +} + // IsParent goes through the layers in the store and checks if i.TopLayer is // the parent of any other layer in store. Double check that image with that // layer exists as well. @@ -522,32 +541,40 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti Ulimit: options.CommonBuildOpts.Ulimit, Volume: options.CommonBuildOpts.Volumes, } - buildinfo := iopodman.BuildInfo{ - AdditionalTags: options.AdditionalTags, - Annotations: options.Annotations, - BuildArgs: options.Args, - BuildOptions: buildOptions, - CniConfigDir: options.CNIConfigDir, - CniPluginDir: options.CNIPluginPath, - Compression: string(options.Compression), - DefaultsMountFilePath: options.DefaultMountsFilePath, - Dockerfiles: dockerfiles, // Err: string(options.Err), + // Out: + // ReportWriter: + Architecture: options.Architecture, + AddCapabilities: options.AddCapabilities, + AdditionalTags: options.AdditionalTags, + Annotations: options.Annotations, + BuildArgs: options.Args, + BuildOptions: buildOptions, + CniConfigDir: options.CNIConfigDir, + CniPluginDir: options.CNIPluginPath, + Compression: string(options.Compression), + Devices: options.Devices, + DefaultsMountFilePath: options.DefaultMountsFilePath, + Dockerfiles: dockerfiles, + DropCapabilities: options.DropCapabilities, ForceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, Iidfile: options.IIDFile, Label: options.Labels, Layers: options.Layers, - Nocache: options.NoCache, - // Out: + // NamespaceOptions: options.NamespaceOptions, + Nocache: options.NoCache, + Os: options.OS, Output: options.Output, OutputFormat: options.OutputFormat, PullPolicy: options.PullPolicy.String(), Quiet: options.Quiet, RemoteIntermediateCtrs: options.RemoveIntermediateCtrs, - // ReportWriter: - RuntimeArgs: options.RuntimeArgs, - Squash: options.Squash, + RuntimeArgs: options.RuntimeArgs, + SignBy: options.SignBy, + Squash: options.Squash, + Target: options.Target, + TransientMounts: options.TransientMounts, } // tar the file outputFile, err := ioutil.TempFile("", "varlink_tar_send") diff --git a/pkg/adapter/sigproxy_linux.go b/pkg/adapter/sigproxy_linux.go index ebfeab725..5695d0e42 100644 --- a/pkg/adapter/sigproxy_linux.go +++ b/pkg/adapter/sigproxy_linux.go @@ -5,7 +5,7 @@ import ( "syscall" "github.com/containers/libpod/libpod" - "github.com/docker/docker/pkg/signal" + "github.com/containers/libpod/pkg/signal" "github.com/sirupsen/logrus" ) @@ -20,16 +20,25 @@ func ProxySignals(ctr *libpod.Container) { for s := range sigBuffer { // Ignore SIGCHLD and SIGPIPE - these are mostly likely // intended for the podman command itself. - if s == signal.SIGCHLD || s == signal.SIGPIPE { + // SIGURG was added because of golang 1.14 and its preemptive changes + // causing more signals to "show up". + // https://github.com/containers/libpod/issues/5483 + if s == syscall.SIGCHLD || s == syscall.SIGPIPE || s == syscall.SIGURG { continue } if err := ctr.Kill(uint(s.(syscall.Signal))); err != nil { + // If the container dies, and we find out here, + // we need to forward that one signal to + // ourselves so that it is not lost, and then + // we terminate the proxy and let the defaults + // play out. logrus.Errorf("Error forwarding signal %d to container %s: %v", s, ctr.ID(), err) signal.StopCatch(sigBuffer) if err := syscall.Kill(syscall.Getpid(), s.(syscall.Signal)); err != nil { logrus.Errorf("failed to kill pid %d", syscall.Getpid()) } + return } } }() diff --git a/pkg/adapter/terminal.go b/pkg/adapter/terminal.go index 51b747d23..499e77def 100644 --- a/pkg/adapter/terminal.go +++ b/pkg/adapter/terminal.go @@ -3,9 +3,9 @@ package adapter import ( "context" "os" - gosignal "os/signal" + "os/signal" - "github.com/docker/docker/pkg/signal" + lsignal "github.com/containers/libpod/pkg/signal" "github.com/docker/docker/pkg/term" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -33,7 +33,7 @@ func getResize() *remotecommand.TerminalSize { // Helper for prepareAttach - set up a goroutine to generate terminal resize events func resizeTty(ctx context.Context, resize chan remotecommand.TerminalSize) { sigchan := make(chan os.Signal, 1) - gosignal.Notify(sigchan, signal.SIGWINCH) + signal.Notify(sigchan, lsignal.SIGWINCH) go func() { defer close(resize) // Update the terminal size immediately without waiting diff --git a/pkg/adapter/terminal_linux.go b/pkg/adapter/terminal_linux.go index 3dc5864e2..ef5a6f926 100644 --- a/pkg/adapter/terminal_linux.go +++ b/pkg/adapter/terminal_linux.go @@ -16,7 +16,6 @@ import ( // ExecAttachCtr execs and attaches to a container func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *libpod.AttachStreams, preserveFDs uint, detachKeys string) (int, error) { resize := make(chan remotecommand.TerminalSize) - haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) // Check if we are attached to a terminal. If we are, generate resize @@ -33,7 +32,18 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged b } }() } - return ctr.Exec(tty, privileged, env, cmd, user, workDir, streams, preserveFDs, resize, detachKeys) + + execConfig := new(libpod.ExecConfig) + execConfig.Command = cmd + execConfig.Terminal = tty + execConfig.Privileged = privileged + execConfig.Environment = env + execConfig.User = user + execConfig.WorkDir = workDir + execConfig.DetachKeys = &detachKeys + execConfig.PreserveFDs = preserveFDs + + return ctr.Exec(execConfig, streams, resize) } // StartAttachCtr starts and (if required) attaches to a container diff --git a/pkg/adapter/terminal_unsupported.go b/pkg/adapter/terminal_unsupported.go new file mode 100644 index 000000000..3009f0a38 --- /dev/null +++ b/pkg/adapter/terminal_unsupported.go @@ -0,0 +1,23 @@ +// +build !linux + +package adapter + +import ( + "context" + "os" + + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/libpod/define" +) + +// ExecAttachCtr execs and attaches to a container +func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *libpod.AttachStreams, preserveFDs uint, detachKeys string) (int, error) { + return -1, define.ErrNotImplemented +} + +// StartAttachCtr starts and (if required) attaches to a container +// if you change the signature of this function from os.File to io.Writer, it will trigger a downstream +// error. we may need to just lint disable this one. +func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error { //nolint-interfacer + return define.ErrNotImplemented +} |