summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/containers_prune.go4
-rw-r--r--cmd/podman/runlabel.go33
-rw-r--r--cmd/podmanV2/Makefile4
-rw-r--r--cmd/podmanV2/common/create.go11
-rw-r--r--cmd/podmanV2/common/default.go13
-rw-r--r--cmd/podmanV2/containers/prune.go86
-rw-r--r--libpod/define/ctr_inspect.go (renamed from libpod/define/inspect.go)0
-rw-r--r--libpod/define/info.go1
-rw-r--r--libpod/define/pod_inspect.go97
-rw-r--r--libpod/info.go5
-rw-r--r--libpod/runtime.go4
-rw-r--r--libpod/runtime_ctr.go3
-rw-r--r--pkg/api/handlers/compat/containers_prune.go29
-rw-r--r--pkg/api/handlers/libpod/volumes.go4
-rw-r--r--pkg/api/handlers/utils/containers.go21
-rw-r--r--pkg/api/handlers/utils/pods.go33
-rw-r--r--pkg/bindings/containers/containers.go10
-rw-r--r--pkg/bindings/test/containers_test.go65
-rw-r--r--pkg/domain/entities/container_ps.go4
-rw-r--r--pkg/domain/entities/containers.go16
-rw-r--r--pkg/domain/entities/engine_container.go1
-rw-r--r--pkg/domain/infra/abi/containers.go24
-rw-r--r--pkg/domain/infra/runtime_libpod.go2
-rw-r--r--pkg/domain/infra/tunnel/containers.go4
-rw-r--r--pkg/ps/define/types.go8
-rw-r--r--pkg/ps/ps.go38
-rw-r--r--pkg/specgen/container_validate.go12
-rw-r--r--pkg/specgen/generate/container.go8
-rw-r--r--pkg/specgen/security.go46
-rw-r--r--pkg/specgen/specgen.go8
-rw-r--r--pkg/util/utils.go33
31 files changed, 459 insertions, 168 deletions
diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go
index cd9817e7e..3953a489d 100644
--- a/cmd/podman/containers_prune.go
+++ b/cmd/podman/containers_prune.go
@@ -19,12 +19,12 @@ var (
pruneContainersDescription = `
podman container prune
- Removes all exited containers
+ Removes all stopped | exited containers
`
_pruneContainersCommand = &cobra.Command{
Use: "prune",
Args: noSubArgs,
- Short: "Remove all stopped containers",
+ Short: "Remove all stopped | exited containers",
Long: pruneContainersDescription,
RunE: func(cmd *cobra.Command, args []string) error {
pruneContainersCommand.InputArgs = args
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index 1ec4da650..193cc5aec 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -13,11 +13,11 @@ import (
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
- "github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
+ "github.com/spf13/pflag"
)
var (
@@ -157,7 +157,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
return errors.Errorf("%s does not have a label of %s", runlabelImage, label)
}
- globalOpts := util.GetGlobalOpts(c)
+ globalOpts := GetGlobalOpts(c)
cmd, env, err := shared.GenerateRunlabelCommand(runLabel, imageName, c.Name, opts, extraArgs, globalOpts)
if err != nil {
return err
@@ -193,3 +193,32 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error {
return utils.ExecCmdWithStdStreams(stdIn, stdOut, stdErr, env, cmd[0], cmd[1:]...)
}
+
+// GetGlobalOpts checks all global flags and generates the command string
+func GetGlobalOpts(c *cliconfig.RunlabelValues) string {
+ globalFlags := map[string]bool{
+ "cgroup-manager": true, "cni-config-dir": true, "conmon": true, "default-mounts-file": true,
+ "hooks-dir": true, "namespace": true, "root": true, "runroot": true,
+ "runtime": true, "storage-driver": true, "storage-opt": true, "syslog": true,
+ "trace": true, "network-cmd-path": true, "config": true, "cpu-profile": true,
+ "log-level": true, "tmpdir": true}
+ const stringSliceType string = "stringSlice"
+
+ var optsCommand []string
+ c.PodmanCommand.Command.Flags().VisitAll(func(f *pflag.Flag) {
+ if !f.Changed {
+ return
+ }
+ if _, exist := globalFlags[f.Name]; exist {
+ if f.Value.Type() == stringSliceType {
+ flagValue := strings.TrimSuffix(strings.TrimPrefix(f.Value.String(), "["), "]")
+ for _, value := range strings.Split(flagValue, ",") {
+ optsCommand = append(optsCommand, fmt.Sprintf("--%s %s", f.Name, value))
+ }
+ } else {
+ optsCommand = append(optsCommand, fmt.Sprintf("--%s %s", f.Name, f.Value.String()))
+ }
+ }
+ })
+ return strings.Join(optsCommand, " ")
+}
diff --git a/cmd/podmanV2/Makefile b/cmd/podmanV2/Makefile
index 01d551212..c951cbdd9 100644
--- a/cmd/podmanV2/Makefile
+++ b/cmd/podmanV2/Makefile
@@ -1,10 +1,10 @@
all: podman podman-remote
podman:
- CGO_ENABLED=1 GO111MODULE=off go build -tags 'ABISupport systemd varlink seccomp'
+ CGO_ENABLED=1 GO111MODULE=off go build -tags 'ABISupport systemd varlink seccomp selinux'
podman-remote:
- CGO_ENABLED=1 GO111MODULE=off go build -tags '!ABISupport systemd seccomp' -o podmanV2-remote
+ CGO_ENABLED=1 GO111MODULE=off go build -tags '!ABISupport systemd seccomp selinux' -o podmanV2-remote
clean:
rm podmanV2 podmanV2-remote
diff --git a/cmd/podmanV2/common/create.go b/cmd/podmanV2/common/create.go
index e2eb8cbda..ecaaf38fb 100644
--- a/cmd/podmanV2/common/create.go
+++ b/cmd/podmanV2/common/create.go
@@ -6,7 +6,6 @@ import (
buildahcli "github.com/containers/buildah/pkg/cli"
"github.com/containers/common/pkg/config"
- "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/sirupsen/logrus"
"github.com/spf13/pflag"
)
@@ -214,22 +213,22 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
)
createFlags.StringVar(
&cf.HealthInterval,
- "health-interval", cliconfig.DefaultHealthCheckInterval,
+ "health-interval", DefaultHealthCheckInterval,
"set an interval for the healthchecks (a value of disable results in no automatic timer setup)",
)
createFlags.UintVar(
&cf.HealthRetries,
- "health-retries", cliconfig.DefaultHealthCheckRetries,
+ "health-retries", DefaultHealthCheckRetries,
"the number of retries allowed before a healthcheck is considered to be unhealthy",
)
createFlags.StringVar(
&cf.HealthStartPeriod,
- "health-start-period", cliconfig.DefaultHealthCheckStartPeriod,
+ "health-start-period", DefaultHealthCheckStartPeriod,
"the initialization time needed for a container to bootstrap",
)
createFlags.StringVar(
&cf.HealthTimeout,
- "health-timeout", cliconfig.DefaultHealthCheckTimeout,
+ "health-timeout", DefaultHealthCheckTimeout,
"the maximum time allowed to complete the healthcheck before an interval is considered failed",
)
createFlags.StringVarP(
@@ -244,7 +243,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet {
)
createFlags.StringVar(
&cf.ImageVolume,
- "image-volume", cliconfig.DefaultImageVolume,
+ "image-volume", DefaultImageVolume,
`Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore")`,
)
createFlags.BoolVar(
diff --git a/cmd/podmanV2/common/default.go b/cmd/podmanV2/common/default.go
index b71fcb6f0..bd793f168 100644
--- a/cmd/podmanV2/common/default.go
+++ b/cmd/podmanV2/common/default.go
@@ -12,6 +12,19 @@ import (
"github.com/opencontainers/selinux/go-selinux"
)
+var (
+ // DefaultHealthCheckInterval default value
+ DefaultHealthCheckInterval = "30s"
+ // DefaultHealthCheckRetries default value
+ DefaultHealthCheckRetries uint = 3
+ // DefaultHealthCheckStartPeriod default value
+ DefaultHealthCheckStartPeriod = "0s"
+ // DefaultHealthCheckTimeout default value
+ DefaultHealthCheckTimeout = "30s"
+ // DefaultImageVolume default value
+ DefaultImageVolume = "bind"
+)
+
// TODO these options are directly embedded into many of the CLI cobra values, as such
// this approach will not work in a remote client. so we will need to likely do something like a
// supported and unsupported approach here and backload these options into the specgen
diff --git a/cmd/podmanV2/containers/prune.go b/cmd/podmanV2/containers/prune.go
new file mode 100644
index 000000000..2d3af5d1d
--- /dev/null
+++ b/cmd/podmanV2/containers/prune.go
@@ -0,0 +1,86 @@
+package containers
+
+import (
+ "bufio"
+ "context"
+ "fmt"
+ "net/url"
+ "os"
+ "strings"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/cmd/podmanV2/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ pruneDescription = fmt.Sprintf(`podman container prune
+
+ Removes all stopped | exited containers`)
+ pruneCommand = &cobra.Command{
+ Use: "prune [flags]",
+ Short: "Remove all stopped | exited containers",
+ Long: pruneDescription,
+ RunE: prune,
+ Example: `podman container prune`,
+ }
+ force bool
+ filter = []string{}
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: pruneCommand,
+ Parent: containerCmd,
+ })
+ flags := pruneCommand.Flags()
+ flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation. The default is false")
+ flags.StringArrayVar(&filter, "filter", []string{}, "Provide filter values (e.g. 'label=<key>=<value>')")
+}
+
+func prune(cmd *cobra.Command, args []string) error {
+ var (
+ errs utils.OutputErrors
+ pruneOptions = entities.ContainerPruneOptions{}
+ )
+ if len(args) > 0 {
+ return errors.Errorf("`%s` takes no arguments", cmd.CommandPath())
+ }
+ if !force {
+ reader := bufio.NewReader(os.Stdin)
+ fmt.Println("WARNING! This will remove all stopped containers.")
+ fmt.Print("Are you sure you want to continue? [y/N] ")
+ answer, err := reader.ReadString('\n')
+ if err != nil {
+ return errors.Wrapf(err, "error reading input")
+ }
+ if strings.ToLower(answer)[0] != 'y' {
+ return nil
+ }
+ }
+
+ // TODO Remove once filter refactor is finished and url.Values done.
+ for _, f := range filter {
+ t := strings.SplitN(f, "=", 2)
+ pruneOptions.Filters = make(url.Values)
+ if len(t) < 2 {
+ return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+ }
+ pruneOptions.Filters.Add(t[0], t[1])
+ }
+ responses, err := registry.ContainerEngine().ContainerPrune(context.Background(), pruneOptions)
+
+ if err != nil {
+ return err
+ }
+ for k := range responses.ID {
+ fmt.Println(k)
+ }
+ for _, v := range responses.Err {
+ errs = append(errs, v)
+ }
+ return errs.PrintErrors()
+}
diff --git a/libpod/define/inspect.go b/libpod/define/ctr_inspect.go
index b7cd13f82..b7cd13f82 100644
--- a/libpod/define/inspect.go
+++ b/libpod/define/ctr_inspect.go
diff --git a/libpod/define/info.go b/libpod/define/info.go
index e9809c367..2516cad77 100644
--- a/libpod/define/info.go
+++ b/libpod/define/info.go
@@ -8,6 +8,7 @@ type Info struct {
Host *HostInfo `json:"host"`
Store *StoreInfo `json:"store"`
Registries map[string]interface{} `json:"registries"`
+ Version Version `json:"version"`
}
//HostInfo describes the libpod host
diff --git a/libpod/define/pod_inspect.go b/libpod/define/pod_inspect.go
new file mode 100644
index 000000000..8558c149b
--- /dev/null
+++ b/libpod/define/pod_inspect.go
@@ -0,0 +1,97 @@
+package define
+
+import (
+ "net"
+ "time"
+
+ "github.com/cri-o/ocicni/pkg/ocicni"
+)
+
+// InspectPodData contains detailed information on a pod's configuration and
+// state. It is used as the output of Inspect on pods.
+type InspectPodData struct {
+ // ID is the ID of the pod.
+ ID string `json:"Id"`
+ // Name is the name of the pod.
+ Name string
+ // Namespace is the Libpod namespace the pod is placed in.
+ Namespace string `json:"Namespace,omitempty"`
+ // Created is the time when the pod was created.
+ Created time.Time
+ // Hostname is the hostname that the pod will set.
+ Hostname string
+ // Labels is a set of key-value labels that have been applied to the
+ // pod.
+ Labels map[string]string `json:"Labels,omitempty"`
+ // CreateCgroup is whether this pod will create its own CGroup to group
+ // containers under.
+ CreateCgroup bool
+ // CgroupParent is the parent of the pod's CGroup.
+ CgroupParent string `json:"CgroupParent,omitempty"`
+ // CgroupPath is the path to the pod's CGroup.
+ CgroupPath string `json:"CgroupPath,omitempty"`
+ // CreateInfra is whether this pod will create an infra container to
+ // share namespaces.
+ CreateInfra bool
+ // InfraContainerID is the ID of the pod's infra container, if one is
+ // present.
+ InfraContainerID string `json:"InfraContainerID,omitempty"`
+ // InfraConfig is the configuration of the infra container of the pod.
+ // Will only be set if CreateInfra is true.
+ InfraConfig *InspectPodInfraConfig `json:"InfraConfig,omitempty"`
+ // SharedNamespaces contains a list of namespaces that will be shared by
+ // containers within the pod. Can only be set if CreateInfra is true.
+ SharedNamespaces []string `json:"SharedNamespaces,omitempty"`
+ // NumContainers is the number of containers in the pod, including the
+ // infra container.
+ NumContainers uint
+ // Containers gives a brief summary of all containers in the pod and
+ // their current status.
+ Containers []InspectPodContainerInfo `json:"Containers,omitempty"`
+}
+
+// InspectPodInfraConfig contains the configuration of the pod's infra
+// container.
+type InspectPodInfraConfig struct {
+ // PortBindings are ports that will be forwarded to the infra container
+ // and then shared with the pod.
+ PortBindings []ocicni.PortMapping
+ // HostNetwork is whether the infra container (and thus the whole pod)
+ // will use the host's network and not create a network namespace.
+ HostNetwork bool
+ // StaticIP is a static IPv4 that will be assigned to the infra
+ // container and then used by the pod.
+ StaticIP net.IP
+ // StaticMAC is a static MAC address that will be assigned to the infra
+ // container and then used by the pod.
+ StaticMAC net.HardwareAddr
+ // NoManageResolvConf indicates that the pod will not manage resolv.conf
+ // and instead each container will handle their own.
+ NoManageResolvConf bool
+ // DNSServer is a set of DNS Servers that will be used by the infra
+ // container's resolv.conf and shared with the remainder of the pod.
+ DNSServer []string
+ // DNSSearch is a set of DNS search domains that will be used by the
+ // infra container's resolv.conf and shared with the remainder of the
+ // pod.
+ DNSSearch []string
+ // DNSOption is a set of DNS options that will be used by the infra
+ // container's resolv.conf and shared with the remainder of the pod.
+ DNSOption []string
+ // NoManageHosts indicates that the pod will not manage /etc/hosts and
+ // instead each container will handle their own.
+ NoManageHosts bool
+ // HostAdd adds a number of hosts to the infra container's resolv.conf
+ // which will be shared with the rest of the pod.
+ HostAdd []string
+}
+
+// InspectPodContainerInfo contains information on a container in a pod.
+type InspectPodContainerInfo struct {
+ // ID is the ID of the container.
+ ID string `json:"Id"`
+ // Name is the name of the container.
+ Name string
+ // State is the current status of the container.
+ State string
+}
diff --git a/libpod/info.go b/libpod/info.go
index 3cc767be6..d7ed5bb16 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -26,6 +26,11 @@ import (
// Info returns the store and host information
func (r *Runtime) info() (*define.Info, error) {
info := define.Info{}
+ versionInfo, err := define.GetVersion()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting version info")
+ }
+ info.Version = versionInfo
// get host information
hostInfo, err := r.hostInfo()
if err != nil {
diff --git a/libpod/runtime.go b/libpod/runtime.go
index e54f51af1..3b8f9e057 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -798,3 +798,7 @@ func (r *Runtime) mergeDBConfig(dbConfig *DBConfig) error {
}
return nil
}
+
+func (r *Runtime) EnableLabeling() bool {
+ return r.config.Containers.EnableLabeling
+}
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 207ac6477..9d3e69d56 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -887,8 +887,9 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
continue
}
err = r.RemoveContainer(context.Background(), ctr, false, false)
- pruneErrors[ctr.ID()] = err
if err != nil {
+ pruneErrors[ctr.ID()] = err
+ } else {
prunedContainers[ctr.ID()] = size
}
}
diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go
index a56c3903d..b4e98ac1f 100644
--- a/pkg/api/handlers/compat/containers_prune.go
+++ b/pkg/api/handlers/compat/containers_prune.go
@@ -4,8 +4,9 @@ import (
"net/http"
"github.com/containers/libpod/libpod"
- "github.com/containers/libpod/pkg/api/handlers"
+ lpfilters "github.com/containers/libpod/libpod/filters"
"github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
"github.com/docker/docker/api/types"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -15,6 +16,7 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
var (
delContainers []string
space int64
+ filterFuncs []libpod.ContainerFilter
)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
@@ -26,11 +28,15 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String()))
return
}
-
- filterFuncs, err := utils.GenerateFilterFuncsFromMap(runtime, query.Filters)
- if err != nil {
- utils.InternalServerError(w, err)
- return
+ for k, v := range query.Filters {
+ for _, val := range v {
+ generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, val, runtime)
+ if err != nil {
+ utils.InternalServerError(w, err)
+ return
+ }
+ filterFuncs = append(filterFuncs, generatedFunc)
+ }
}
prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs)
if err != nil {
@@ -40,14 +46,11 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) {
// Libpod response differs
if utils.IsLibpodRequest(r) {
- var response []handlers.LibpodContainersPruneReport
- for ctrID, size := range prunedContainers {
- response = append(response, handlers.LibpodContainersPruneReport{ID: ctrID, SpaceReclaimed: size})
- }
- for ctrID, err := range pruneErrors {
- response = append(response, handlers.LibpodContainersPruneReport{ID: ctrID, PruneError: err.Error()})
+ report := &entities.ContainerPruneReport{
+ Err: pruneErrors,
+ ID: prunedContainers,
}
- utils.WriteResponse(w, http.StatusOK, response)
+ utils.WriteResponse(w, http.StatusOK, report)
return
}
for ctrID, size := range prunedContainers {
diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go
index 5a6fc021e..18c561a0d 100644
--- a/pkg/api/handlers/libpod/volumes.go
+++ b/pkg/api/handlers/libpod/volumes.go
@@ -4,12 +4,12 @@ import (
"encoding/json"
"net/http"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/api/handlers/utils"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/domain/filters"
+ "github.com/containers/libpod/pkg/domain/infra/abi/parse"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -46,7 +46,7 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(input.Label))
}
if len(input.Options) > 0 {
- parsedOptions, err := shared.ParseVolumeOptions(input.Options)
+ parsedOptions, err := parse.ParseVolumeOptions(input.Options)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/utils/containers.go b/pkg/api/handlers/utils/containers.go
index bbe4cee3c..d1107f67c 100644
--- a/pkg/api/handlers/utils/containers.go
+++ b/pkg/api/handlers/utils/containers.go
@@ -6,9 +6,10 @@ import (
"time"
"github.com/containers/libpod/cmd/podman/shared"
+ createconfig "github.com/containers/libpod/pkg/spec"
+
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
- createconfig "github.com/containers/libpod/pkg/spec"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -68,24 +69,6 @@ func WaitContainer(w http.ResponseWriter, r *http.Request) (int32, error) {
return con.WaitForConditionWithInterval(interval, condition)
}
-// GenerateFilterFuncsFromMap is used to generate un-executed functions that can be used to filter
-// containers. It is specifically designed for the RESTFUL API input.
-func GenerateFilterFuncsFromMap(r *libpod.Runtime, filters map[string][]string) ([]libpod.ContainerFilter, error) {
- var (
- filterFuncs []libpod.ContainerFilter
- )
- for k, v := range filters {
- for _, val := range v {
- f, err := shared.GenerateContainerFilterFuncs(k, val, r)
- if err != nil {
- return filterFuncs, err
- }
- filterFuncs = append(filterFuncs, f)
- }
- }
- return filterFuncs, nil
-}
-
func CreateContainer(ctx context.Context, w http.ResponseWriter, runtime *libpod.Runtime, cc *createconfig.CreateConfig) {
var pod *libpod.Pod
ctr, err := shared.CreateContainerFromCreateConfig(runtime, cc, ctx, pod)
diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go
index d47053eda..fb795fa6a 100644
--- a/pkg/api/handlers/utils/pods.go
+++ b/pkg/api/handlers/utils/pods.go
@@ -1,20 +1,19 @@
package utils
import (
- "fmt"
"net/http"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ lpfilters "github.com/containers/libpod/libpod/filters"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/gorilla/schema"
)
func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport, error) {
var (
- lps []*entities.ListPodsReport
- pods []*libpod.Pod
- podErr error
+ lps []*entities.ListPodsReport
+ pods []*libpod.Pod
+ filters []libpod.PodFilter
)
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
@@ -28,28 +27,24 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
return nil, err
}
- var filters = []string{}
if _, found := r.URL.Query()["digests"]; found && query.Digests {
UnSupportedParameter("digests")
}
- if len(query.Filters) > 0 {
- for k, v := range query.Filters {
- for _, val := range v {
- filters = append(filters, fmt.Sprintf("%s=%s", k, val))
+ for k, v := range query.Filters {
+ for _, filter := range v {
+ f, err := lpfilters.GeneratePodFilterFunc(k, filter)
+ if err != nil {
+ return nil, err
}
+ filters = append(filters, f)
}
- filterFuncs, err := shared.GenerateFilterFunction(runtime, filters)
- if err != nil {
- return nil, err
- }
- pods, podErr = shared.FilterAllPodsWithFilterFunc(runtime, filterFuncs...)
- } else {
- pods, podErr = runtime.GetAllPods()
}
- if podErr != nil {
- return nil, podErr
+ pods, err := runtime.Pods(filters...)
+ if err != nil {
+ return nil, err
}
+
for _, pod := range pods {
status, err := pod.GetPodStatus()
if err != nil {
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index 963f0ec57..e74a256c7 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -60,10 +60,8 @@ func List(ctx context.Context, filters map[string][]string, all *bool, last *int
// used for more granular selection of containers. The main error returned indicates if there were runtime
// errors like finding containers. Errors specific to the removal of a container are in the PruneContainerResponse
// structure.
-func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
- var (
- pruneResponse []string
- )
+func Prune(ctx context.Context, filters map[string][]string) (*entities.ContainerPruneReport, error) {
+ var reports *entities.ContainerPruneReport
conn, err := bindings.GetClient(ctx)
if err != nil {
return nil, err
@@ -78,9 +76,9 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) {
}
response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params)
if err != nil {
- return pruneResponse, err
+ return nil, err
}
- return pruneResponse, response.Process(pruneResponse)
+ return reports, response.Process(&reports)
}
// Remove removes a container from local storage. The force bool designates
diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go
index 0b1b9ecdd..e288dc368 100644
--- a/pkg/bindings/test/containers_test.go
+++ b/pkg/bindings/test/containers_test.go
@@ -531,4 +531,69 @@ var _ = Describe("Podman containers ", func() {
Expect(err).ToNot(BeNil())
})
+ It("podman prune stoped containers", func() {
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ // Prune container should return no errors and one pruned container ID.
+ pruneResponse, err := containers.Prune(bt.conn, nil)
+ Expect(err).To(BeNil())
+ Expect(len(pruneResponse.Err)).To(Equal(0))
+ Expect(len(pruneResponse.ID)).To(Equal(1))
+ })
+
+ It("podman prune stoped containers with filters", func() {
+ // Start and stop a container to enter in exited state.
+ var name = "top"
+ _, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+ err = containers.Stop(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+
+ // Invalid filter keys should return error.
+ filtersIncorrect := map[string][]string{
+ "status": {"dummy"},
+ }
+ pruneResponse, err := containers.Prune(bt.conn, filtersIncorrect)
+ Expect(err).ToNot(BeNil())
+
+ // Mismatched filter params no container should be pruned.
+ filtersIncorrect = map[string][]string{
+ "name": {"r"},
+ }
+ pruneResponse, err = containers.Prune(bt.conn, filtersIncorrect)
+ Expect(err).To(BeNil())
+ Expect(len(pruneResponse.Err)).To(Equal(0))
+ Expect(len(pruneResponse.ID)).To(Equal(0))
+
+ // Valid filter params container should be pruned now.
+ filters := map[string][]string{
+ "name": {"top"},
+ }
+ pruneResponse, err = containers.Prune(bt.conn, filters)
+ Expect(err).To(BeNil())
+ Expect(len(pruneResponse.Err)).To(Equal(0))
+ Expect(len(pruneResponse.ID)).To(Equal(1))
+ })
+
+ It("podman prune running containers", func() {
+ // Start the container.
+ var name = "top"
+ _, err := bt.RunTopContainer(&name, &bindings.PFalse, nil)
+ Expect(err).To(BeNil())
+
+ // Check if the container is running.
+ data, err := containers.Inspect(bt.conn, name, nil)
+ Expect(err).To(BeNil())
+ Expect(data.State.Status).To(Equal("running"))
+
+ // Prune. Should return no error no prune response ID.
+ pruneResponse, err := containers.Prune(bt.conn, nil)
+ Expect(err).To(BeNil())
+ Expect(len(pruneResponse.ID)).To(Equal(0))
+ })
})
diff --git a/pkg/domain/entities/container_ps.go b/pkg/domain/entities/container_ps.go
index ceafecebc..33f5d0500 100644
--- a/pkg/domain/entities/container_ps.go
+++ b/pkg/domain/entities/container_ps.go
@@ -4,8 +4,8 @@ import (
"sort"
"strings"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/ps/define"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
)
@@ -48,7 +48,7 @@ type ListContainer struct {
// Port mappings
Ports []ocicni.PortMapping
// Size of the container rootfs. Requires the size boolean to be true
- Size *shared.ContainerSize
+ Size *define.ContainerSize
// Time when container started
StartedAt int64
// State of container
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index f21af9ce4..52327a905 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -2,6 +2,7 @@ package entities
import (
"io"
+ "net/url"
"os"
"time"
@@ -260,7 +261,7 @@ type ContainerRunOptions struct {
}
// ContainerRunReport describes the results of running
-//a container
+// a container
type ContainerRunReport struct {
ExitCode int
Id string
@@ -327,3 +328,16 @@ type ContainerUnmountReport struct {
Err error
Id string
}
+
+// ContainerPruneOptions describes the options needed
+// to prune a container from the CLI
+type ContainerPruneOptions struct {
+ Filters url.Values `json:"filters" schema:"filters"`
+}
+
+// ContainerPruneReport describes the results after pruning the
+// stopped containers.
+type ContainerPruneReport struct {
+ ID map[string]int64
+ Err map[string]error
+}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 5fdb9a8a6..c3092a98a 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -13,6 +13,7 @@ type ContainerEngine interface {
ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error
ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error)
ContainerCleanup(ctx context.Context, namesOrIds []string, options ContainerCleanupOptions) ([]*ContainerCleanupReport, error)
+ ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error)
ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, error)
ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error)
ContainerDiff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error)
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index f464df3ac..4279fb756 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -11,6 +11,8 @@ import (
"strings"
"sync"
+ lpfilters "github.com/containers/libpod/libpod/filters"
+
"github.com/containers/buildah"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/manifest"
@@ -173,6 +175,28 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin
return reports, nil
}
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
+ var filterFuncs []libpod.ContainerFilter
+ for k, v := range options.Filters {
+ for _, val := range v {
+ generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, val, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ filterFuncs = append(filterFuncs, generatedFunc)
+ }
+ }
+ prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs)
+ if err != nil {
+ return nil, err
+ }
+ report := entities.ContainerPruneReport{
+ ID: prunedContainers,
+ Err: pruneErrors,
+ }
+ return &report, nil
+}
+
func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
var (
reports []*entities.KillReport
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index 9cf374e2e..6b0ac4852 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -160,7 +160,7 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
}
if fs.Changed("runtime") {
- options = append(options, libpod.WithOCIRuntime(cfg.RuntimePath))
+ options = append(options, libpod.WithOCIRuntime(cfg.Engine.OCIRuntime))
}
if fs.Changed("conmon") {
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 05b62efcf..679bb371b 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -146,6 +146,10 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
return reports, nil
}
+func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) {
+ return containers.Prune(ic.ClientCxt, options.Filters)
+}
+
func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) {
var (
reports []*entities.ContainerInspectReport
diff --git a/pkg/ps/define/types.go b/pkg/ps/define/types.go
new file mode 100644
index 000000000..878653c3a
--- /dev/null
+++ b/pkg/ps/define/types.go
@@ -0,0 +1,8 @@
+package define
+
+// ContainerSize holds the size of the container's root filesystem and top
+// read-write layer.
+type ContainerSize struct {
+ RootFsSize int64 `json:"rootFsSize"`
+ RwSize int64 `json:"rwSize"`
+}
diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go
index 58fcc2c21..8b62fc307 100644
--- a/pkg/ps/ps.go
+++ b/pkg/ps/ps.go
@@ -1,16 +1,19 @@
package ps
import (
+ "os"
"path/filepath"
+ "regexp"
"sort"
"strconv"
+ "strings"
"time"
- "github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/define"
lpfilters "github.com/containers/libpod/libpod/filters"
"github.com/containers/libpod/pkg/domain/entities"
+ psdefine "github.com/containers/libpod/pkg/ps/define"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -80,7 +83,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
exitCode int32
exited bool
pid int
- size *shared.ContainerSize
+ size *psdefine.ContainerSize
startedTime time.Time
exitedTime time.Time
cgroup, ipc, mnt, net, pidns, user, uts string
@@ -116,16 +119,16 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
return errors.Wrapf(err, "unable to obtain container pid")
}
ctrPID := strconv.Itoa(pid)
- cgroup, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
- ipc, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
- mnt, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
- net, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
- pidns, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
- user, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
- uts, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
+ cgroup, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
+ ipc, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
+ mnt, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
+ net, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
+ pidns, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
+ user, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
+ uts, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
}
if opts.Size {
- size = new(shared.ContainerSize)
+ size = new(psdefine.ContainerSize)
rootFsSize, err := c.RootFsSize()
if err != nil {
@@ -187,3 +190,18 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
}
return ps, nil
}
+
+func getNamespaceInfo(path string) (string, error) {
+ val, err := os.Readlink(path)
+ if err != nil {
+ return "", errors.Wrapf(err, "error getting info from %q", path)
+ }
+ return getStrFromSquareBrackets(val), nil
+}
+
+// getStrFromSquareBrackets gets the string inside [] from a string.
+func getStrFromSquareBrackets(cmd string) string {
+ reg := regexp.MustCompile(`.*\[|\].*`)
+ arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",")
+ return strings.Join(arr, ",")
+}
diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go
index aad14ddcb..9152e7ee7 100644
--- a/pkg/specgen/container_validate.go
+++ b/pkg/specgen/container_validate.go
@@ -68,18 +68,6 @@ func (s *SpecGenerator) Validate() error {
if len(s.CapAdd) > 0 && s.Privileged {
return exclusiveOptions("CapAdd", "privileged")
}
- // selinuxprocesslabel and privileged are exclusive
- if len(s.SelinuxProcessLabel) > 0 && s.Privileged {
- return exclusiveOptions("SelinuxProcessLabel", "privileged")
- }
- // selinuxmounmtlabel and privileged are exclusive
- if len(s.SelinuxMountLabel) > 0 && s.Privileged {
- return exclusiveOptions("SelinuxMountLabel", "privileged")
- }
- // selinuxopts and privileged are exclusive
- if len(s.SelinuxOpts) > 0 && s.Privileged {
- return exclusiveOptions("SelinuxOpts", "privileged")
- }
// apparmor and privileged are exclusive
if len(s.ApparmorProfile) > 0 && s.Privileged {
return exclusiveOptions("AppArmorProfile", "privileged")
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 78c77fec1..edd54847d 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -113,6 +113,14 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat
if err := finishThrottleDevices(s); err != nil {
return err
}
+ // Unless already set via the CLI, check if we need to disable process
+ // labels or set the defaults.
+ if len(s.SelinuxOpts) == 0 {
+ if err := s.SetLabelOpts(r, s.PidNS, s.IpcNS); err != nil {
+ return err
+ }
+ }
+
return nil
}
diff --git a/pkg/specgen/security.go b/pkg/specgen/security.go
index 158e4a7b3..6f835eae4 100644
--- a/pkg/specgen/security.go
+++ b/pkg/specgen/security.go
@@ -1,32 +1,26 @@
package specgen
-// ToCreateOptions convert the SecurityConfig to a slice of container create
-// options.
-/*
-func (c *SecurityConfig) ToCreateOptions() ([]libpod.CtrCreateOption, error) {
- options := make([]libpod.CtrCreateOption, 0)
- options = append(options, libpod.WithSecLabels(c.LabelOpts))
- options = append(options, libpod.WithPrivileged(c.Privileged))
- return options, nil
-}
-*/
+import (
+ "github.com/containers/libpod/libpod"
+ "github.com/opencontainers/selinux/go-selinux/label"
+ "github.com/pkg/errors"
+)
// SetLabelOpts sets the label options of the SecurityConfig according to the
// input.
-/*
-func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidConfig, ipcConfig *IpcConfig) error {
- if c.Privileged {
- c.LabelOpts = label.DisableSecOpt()
+func (s *SpecGenerator) SetLabelOpts(runtime *libpod.Runtime, pidConfig Namespace, ipcConfig Namespace) error {
+ if !runtime.EnableLabeling() || s.Privileged {
+ s.SelinuxOpts = label.DisableSecOpt()
return nil
}
var labelOpts []string
- if pidConfig.PidMode.IsHost() {
+ if pidConfig.IsHost() {
labelOpts = append(labelOpts, label.DisableSecOpt()...)
- } else if pidConfig.PidMode.IsContainer() {
- ctr, err := runtime.LookupContainer(pidConfig.PidMode.Container())
+ } else if pidConfig.IsContainer() {
+ ctr, err := runtime.LookupContainer(pidConfig.Value)
if err != nil {
- return errors.Wrapf(err, "container %q not found", pidConfig.PidMode.Container())
+ return errors.Wrapf(err, "container %q not found", pidConfig.Value)
}
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
if err != nil {
@@ -35,12 +29,12 @@ func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidCon
labelOpts = append(labelOpts, secopts...)
}
- if ipcConfig.IpcMode.IsHost() {
+ if ipcConfig.IsHost() {
labelOpts = append(labelOpts, label.DisableSecOpt()...)
- } else if ipcConfig.IpcMode.IsContainer() {
- ctr, err := runtime.LookupContainer(ipcConfig.IpcMode.Container())
+ } else if ipcConfig.IsContainer() {
+ ctr, err := runtime.LookupContainer(ipcConfig.Value)
if err != nil {
- return errors.Wrapf(err, "container %q not found", ipcConfig.IpcMode.Container())
+ return errors.Wrapf(err, "container %q not found", ipcConfig.Value)
}
secopts, err := label.DupSecOpt(ctr.ProcessLabel())
if err != nil {
@@ -49,13 +43,7 @@ func (c *SecurityConfig) SetLabelOpts(runtime *libpod.Runtime, pidConfig *PidCon
labelOpts = append(labelOpts, secopts...)
}
- c.LabelOpts = append(c.LabelOpts, labelOpts...)
- return nil
-}
-*/
-
-// SetSecurityOpts the the security options (labels, apparmor, seccomp, etc.).
-func SetSecurityOpts(securityOpts []string) error {
+ s.SelinuxOpts = append(s.SelinuxOpts, labelOpts...)
return nil
}
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 8482ef2c9..1a05733f9 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -228,14 +228,6 @@ type ContainerSecurityConfig struct {
// If SELinux is enabled and this is not specified, a label will be
// automatically generated if not specified.
// Optional.
- SelinuxProcessLabel string `json:"selinux_process_label,omitempty"`
- // SelinuxMountLabel is the mount label the container will use.
- // If SELinux is enabled and this is not specified, a label will be
- // automatically generated if not specified.
- // Optional.
- SelinuxMountLabel string `json:"selinux_mount_label,omitempty"`
- // SelinuxOpts are options for configuring SELinux.
- // Optional.
SelinuxOpts []string `json:"selinux_opts,omitempty"`
// ApparmorProfile is the name of the Apparmor profile the container
// will use.
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 2500693d7..babf7dfc9 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -14,7 +14,6 @@ import (
"github.com/BurntSushi/toml"
"github.com/containers/image/v5/types"
- "github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
@@ -25,7 +24,6 @@ import (
"github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/spf13/pflag"
"golang.org/x/crypto/ssh/terminal"
)
@@ -516,37 +514,6 @@ func ParseInputTime(inputTime string) (time.Time, error) {
return time.Now().Add(-duration), nil
}
-// GetGlobalOpts checks all global flags and generates the command string
-// FIXME: Port input to config.Config
-// TODO: Is there a "better" way to reverse values to flags? This seems brittle.
-func GetGlobalOpts(c *cliconfig.RunlabelValues) string {
- globalFlags := map[string]bool{
- "cgroup-manager": true, "cni-config-dir": true, "conmon": true, "default-mounts-file": true,
- "hooks-dir": true, "namespace": true, "root": true, "runroot": true,
- "runtime": true, "storage-driver": true, "storage-opt": true, "syslog": true,
- "trace": true, "network-cmd-path": true, "config": true, "cpu-profile": true,
- "log-level": true, "tmpdir": true}
- const stringSliceType string = "stringSlice"
-
- var optsCommand []string
- c.PodmanCommand.Command.Flags().VisitAll(func(f *pflag.Flag) {
- if !f.Changed {
- return
- }
- if _, exist := globalFlags[f.Name]; exist {
- if f.Value.Type() == stringSliceType {
- flagValue := strings.TrimSuffix(strings.TrimPrefix(f.Value.String(), "["), "]")
- for _, value := range strings.Split(flagValue, ",") {
- optsCommand = append(optsCommand, fmt.Sprintf("--%s %s", f.Name, value))
- }
- } else {
- optsCommand = append(optsCommand, fmt.Sprintf("--%s %s", f.Name, f.Value.String()))
- }
- }
- })
- return strings.Join(optsCommand, " ")
-}
-
// OpenExclusiveFile opens a file for writing and ensure it doesn't already exist
func OpenExclusiveFile(path string) (*os.File, error) {
baseDir := filepath.Dir(path)