summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/common/completion.go132
-rw-r--r--cmd/podman/common/netflags.go34
-rw-r--r--cmd/podman/containers/top.go8
-rw-r--r--cmd/podman/pods/create.go30
-rw-r--r--cmd/podman/root.go52
-rw-r--r--docs/source/markdown/podman-create.1.md2
-rw-r--r--docs/source/markdown/podman-run.1.md2
-rw-r--r--docs/source/markdown/podman-top.1.md2
-rw-r--r--libpod/container.go20
-rw-r--r--libpod/container_internal.go9
-rw-r--r--libpod/networking_linux.go21
-rw-r--r--libpod/rootless_cni_linux.go4
-rw-r--r--pkg/api/handlers/compat/containers.go9
-rw-r--r--pkg/domain/entities/images.go8
-rw-r--r--pkg/specgen/namespaces.go6
-rw-r--r--test/e2e/pod_create_test.go20
-rw-r--r--test/e2e/run_networking_test.go29
17 files changed, 236 insertions, 152 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index db4d3d0d3..c96f7436d 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/registries"
+ "github.com/containers/podman/v2/pkg/rootless"
systemdGen "github.com/containers/podman/v2/pkg/systemd/generate"
"github.com/spf13/cobra"
)
@@ -36,7 +37,35 @@ const (
type keyValueCompletion map[string]func(s string) ([]string, cobra.ShellCompDirective)
-func getContainers(toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
+func setupContainerEngine(cmd *cobra.Command) (entities.ContainerEngine, error) {
+ containerEngine, err := registry.NewContainerEngine(cmd, []string{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, err
+ }
+ if !registry.IsRemote() && rootless.IsRootless() {
+ err := containerEngine.SetupRootless(registry.Context(), cmd)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return containerEngine, nil
+}
+
+func setupImageEngine(cmd *cobra.Command) (entities.ImageEngine, error) {
+ imageEngine, err := registry.NewImageEngine(cmd, []string{})
+ if err != nil {
+ return nil, err
+ }
+ // we also need to set up the container engine since this
+ // is required to setup the rootless namespace
+ if _, err = setupContainerEngine(cmd); err != nil {
+ return nil, err
+ }
+ return imageEngine, nil
+}
+
+func getContainers(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
suggestions := []string{}
listOpts := entities.ContainerListOptions{
Filters: make(map[string][]string),
@@ -47,7 +76,12 @@ func getContainers(toComplete string, cType completeType, statuses ...string) ([
listOpts.Filters["status"] = statuses
}
- containers, err := registry.ContainerEngine().ContainerList(registry.GetContext(), listOpts)
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ containers, err := engine.ContainerList(registry.GetContext(), listOpts)
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveError
@@ -68,7 +102,7 @@ func getContainers(toComplete string, cType completeType, statuses ...string) ([
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
-func getPods(toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
+func getPods(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) {
suggestions := []string{}
listOpts := entities.PodPSOptions{
Filters: make(map[string][]string),
@@ -77,7 +111,12 @@ func getPods(toComplete string, cType completeType, statuses ...string) ([]strin
listOpts.Filters["status"] = statuses
}
- pods, err := registry.ContainerEngine().PodPs(registry.GetContext(), listOpts)
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ pods, err := engine.PodPs(registry.GetContext(), listOpts)
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveError
@@ -98,11 +137,16 @@ func getPods(toComplete string, cType completeType, statuses ...string) ([]strin
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
-func getVolumes(toComplete string) ([]string, cobra.ShellCompDirective) {
+func getVolumes(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
suggestions := []string{}
lsOpts := entities.VolumeListOptions{}
- volumes, err := registry.ContainerEngine().VolumeList(registry.GetContext(), lsOpts)
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ volumes, err := engine.VolumeList(registry.GetContext(), lsOpts)
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveError
@@ -116,11 +160,16 @@ func getVolumes(toComplete string) ([]string, cobra.ShellCompDirective) {
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
-func getImages(toComplete string) ([]string, cobra.ShellCompDirective) {
+func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
suggestions := []string{}
listOptions := entities.ImageListOptions{}
- images, err := registry.ImageEngine().List(registry.GetContext(), listOptions)
+ engine, err := setupImageEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ images, err := engine.List(registry.GetContext(), listOptions)
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveError
@@ -171,11 +220,16 @@ func getRegistries() ([]string, cobra.ShellCompDirective) {
return regs, cobra.ShellCompDirectiveNoFileComp
}
-func getNetworks(toComplete string) ([]string, cobra.ShellCompDirective) {
+func getNetworks(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
suggestions := []string{}
networkListOptions := entities.NetworkListOptions{}
- networks, err := registry.ContainerEngine().NetworkList(registry.Context(), networkListOptions)
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ networks, err := engine.NetworkList(registry.Context(), networkListOptions)
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveError
@@ -266,7 +320,7 @@ func AutocompleteContainers(cmd *cobra.Command, args []string, toComplete string
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, completeDefault)
+ return getContainers(cmd, toComplete, completeDefault)
}
// AutocompleteContainersCreated - Autocomplete only created container names.
@@ -274,7 +328,7 @@ func AutocompleteContainersCreated(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, completeDefault, "created")
+ return getContainers(cmd, toComplete, completeDefault, "created")
}
// AutocompleteContainersExited - Autocomplete only exited container names.
@@ -282,7 +336,7 @@ func AutocompleteContainersExited(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, completeDefault, "exited")
+ return getContainers(cmd, toComplete, completeDefault, "exited")
}
// AutocompleteContainersPaused - Autocomplete only paused container names.
@@ -290,7 +344,7 @@ func AutocompleteContainersPaused(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, completeDefault, "paused")
+ return getContainers(cmd, toComplete, completeDefault, "paused")
}
// AutocompleteContainersRunning - Autocomplete only running container names.
@@ -298,7 +352,7 @@ func AutocompleteContainersRunning(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, completeDefault, "running")
+ return getContainers(cmd, toComplete, completeDefault, "running")
}
// AutocompleteContainersStartable - Autocomplete only created and exited container names.
@@ -306,7 +360,7 @@ func AutocompleteContainersStartable(cmd *cobra.Command, args []string, toComple
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, completeDefault, "created", "exited")
+ return getContainers(cmd, toComplete, completeDefault, "created", "exited")
}
// AutocompletePods - Autocomplete all pod names.
@@ -314,7 +368,7 @@ func AutocompletePods(cmd *cobra.Command, args []string, toComplete string) ([]s
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getPods(toComplete, completeDefault)
+ return getPods(cmd, toComplete, completeDefault)
}
// AutocompletePodsRunning - Autocomplete only running pod names.
@@ -323,7 +377,7 @@ func AutocompletePodsRunning(cmd *cobra.Command, args []string, toComplete strin
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getPods(toComplete, completeDefault, "running", "degraded")
+ return getPods(cmd, toComplete, completeDefault, "running", "degraded")
}
// AutocompleteContainersAndPods - Autocomplete container names and pod names.
@@ -331,8 +385,8 @@ func AutocompleteContainersAndPods(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- containers, _ := getContainers(toComplete, completeDefault)
- pods, _ := getPods(toComplete, completeDefault)
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
+ pods, _ := getPods(cmd, toComplete, completeDefault)
return append(containers, pods...), cobra.ShellCompDirectiveNoFileComp
}
@@ -341,8 +395,8 @@ func AutocompleteContainersAndImages(cmd *cobra.Command, args []string, toComple
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- containers, _ := getContainers(toComplete, completeDefault)
- images, _ := getImages(toComplete)
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
+ images, _ := getImages(cmd, toComplete)
return append(containers, images...), cobra.ShellCompDirectiveNoFileComp
}
@@ -351,7 +405,7 @@ func AutocompleteVolumes(cmd *cobra.Command, args []string, toComplete string) (
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getVolumes(toComplete)
+ return getVolumes(cmd, toComplete)
}
// AutocompleteImages - Autocomplete images.
@@ -359,7 +413,7 @@ func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getImages(toComplete)
+ return getImages(cmd, toComplete)
}
// AutocompleteCreateRun - Autocomplete only the fist argument as image and then do file completion.
@@ -368,7 +422,7 @@ func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string)
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) < 1 {
- return getImages(toComplete)
+ return getImages(cmd, toComplete)
}
// TODO: add path completion for files in the image
return nil, cobra.ShellCompDirectiveDefault
@@ -387,7 +441,7 @@ func AutocompleteNetworks(cmd *cobra.Command, args []string, toComplete string)
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getNetworks(toComplete)
+ return getNetworks(cmd, toComplete)
}
// AutocompleteCpCommand - Autocomplete podman cp command args.
@@ -396,7 +450,7 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) < 2 {
- containers, _ := getContainers(toComplete, completeDefault)
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
for _, container := range containers {
// TODO: Add path completion for inside the container if possible
if strings.HasPrefix(container, toComplete) {
@@ -464,7 +518,7 @@ func AutocompleteCreateAttach(cmd *cobra.Command, args []string, toComplete stri
// -> host,container:[name],ns:[path],private
func AutocompleteNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
kv := keyValueCompletion{
- "container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) },
+ "container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
"ns:": func(s string) ([]string, cobra.ShellCompDirective) { return nil, cobra.ShellCompDirectiveDefault },
"host": nil,
"private": nil,
@@ -623,7 +677,7 @@ func AutocompleteMountFlag(cmd *cobra.Command, args []string, toComplete string)
// AutocompleteVolumeFlag - Autocomplete volume flag options.
// -> volumes and paths
func AutocompleteVolumeFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- volumes, _ := getVolumes(toComplete)
+ volumes, _ := getVolumes(cmd, toComplete)
directive := cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveDefault
if strings.Contains(toComplete, ":") {
// add space after second path
@@ -753,15 +807,15 @@ var containerStatuses = []string{"created", "running", "paused", "stopped", "exi
// AutocompletePsFilters - Autocomplete ps filter options.
func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
kv := keyValueCompletion{
- "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeIDs) },
- "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeNames) },
+ "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) },
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) },
"status=": func(_ string) ([]string, cobra.ShellCompDirective) {
return containerStatuses, cobra.ShellCompDirectiveNoFileComp
},
- "ancestor": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(s) },
- "before=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) },
- "since=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) },
- "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(s) },
+ "ancestor": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) },
+ "before=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "since=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
"health=": func(_ string) ([]string, cobra.ShellCompDirective) {
return []string{define.HealthCheckHealthy,
define.HealthCheckUnhealthy}, cobra.ShellCompDirectiveNoFileComp
@@ -776,14 +830,14 @@ func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string)
// AutocompletePodPsFilters - Autocomplete pod ps filter options.
func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
kv := keyValueCompletion{
- "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(s, completeIDs) },
- "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(s, completeNames) },
+ "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeIDs) },
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeNames) },
"status=": func(_ string) ([]string, cobra.ShellCompDirective) {
return []string{"stopped", "running",
"paused", "exited", "dead", "created", "degraded"}, cobra.ShellCompDirectiveNoFileComp
},
- "ctr-ids=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeIDs) },
- "ctr-names=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeNames) },
+ "ctr-ids=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) },
+ "ctr-names=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) },
"ctr-number=": nil,
"ctr-status=": func(_ string) ([]string, cobra.ShellCompDirective) {
return containerStatuses, cobra.ShellCompDirectiveNoFileComp
diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go
index cae52ccaa..898d65bd0 100644
--- a/cmd/podman/common/netflags.go
+++ b/cmd/podman/common/netflags.go
@@ -59,8 +59,8 @@ func DefineNetFlags(cmd *cobra.Command) {
_ = cmd.RegisterFlagCompletionFunc(macAddressFlagName, completion.AutocompleteNone)
networkFlagName := "network"
- netFlags.String(
- networkFlagName, containerConfig.NetNS(),
+ netFlags.StringArray(
+ networkFlagName, []string{containerConfig.NetNS()},
"Connect a container to a network",
)
_ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworks)
@@ -194,25 +194,29 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
}
if cmd.Flags().Changed("network") {
- network, err := cmd.Flags().GetString("network")
+ networks, err := cmd.Flags().GetStringArray("network")
if err != nil {
return nil, err
}
+ for i, network := range networks {
+ parts := strings.SplitN(network, ":", 2)
- parts := strings.SplitN(network, ":", 2)
-
- ns, cniNets, err := specgen.ParseNetworkNamespace(network)
- if err != nil {
- return nil, err
- }
+ ns, cniNets, err := specgen.ParseNetworkNamespace(network)
+ if err != nil {
+ return nil, err
+ }
+ if i > 0 && (len(cniNets) == 0 || len(opts.CNINetworks) == 0) {
+ return nil, errors.Errorf("network conflict between type %s and %s", opts.Network.NSMode, ns.NSMode)
+ }
- if len(parts) > 1 {
- opts.NetworkOptions = make(map[string][]string)
- opts.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
- cniNets = nil
+ if len(parts) > 1 {
+ opts.NetworkOptions = make(map[string][]string)
+ opts.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
+ cniNets = nil
+ }
+ opts.Network = ns
+ opts.CNINetworks = append(opts.CNINetworks, cniNets...)
}
- opts.Network = ns
- opts.CNINetworks = cniNets
}
aliases, err := cmd.Flags().GetStringSlice("network-alias")
diff --git a/cmd/podman/containers/top.go b/cmd/podman/containers/top.go
index 3eb6d2af2..f00b1dce1 100644
--- a/cmd/podman/containers/top.go
+++ b/cmd/podman/containers/top.go
@@ -18,12 +18,10 @@ import (
)
var (
- topDescription = `Similar to system "top" command.
-
- Specify format descriptors to alter the output.
-
- Running "podman top -l pid pcpu seccomp" will print the process ID, the CPU percentage and the seccomp mode of each process of the latest container.`
+ topDescription = `Display the running processes of a container.
+ The top command extends the ps(1) compatible AIX descriptors with container-specific ones as shown below. In the presence of ps(1) specific flags (e.g, -eo), Podman will execute ps(1) inside the container.
+`
topOptions = entities.TopOptions{}
topCommand = &cobra.Command{
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 449d60bb9..5b0aa2fe4 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -94,7 +94,7 @@ func init() {
flags.StringVar(&podIDFile, podIDFileFlagName, "", "Write the pod ID to the file")
_ = createCommand.RegisterFlagCompletionFunc(podIDFileFlagName, completion.AutocompleteDefault)
- flags.BoolVar(&replace, "replace", false, "If a pod with the same exists, replace it")
+ flags.BoolVar(&replace, "replace", false, "If a pod with the same name exists, replace it")
shareFlagName := "share"
flags.StringVar(&share, shareFlagName, specgen.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
@@ -171,33 +171,7 @@ func create(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- createOptions.Net.Network = specgen.Namespace{}
- if cmd.Flag("network").Changed {
- netInput, err := cmd.Flags().GetString("network")
- if err != nil {
- return err
- }
- parts := strings.SplitN(netInput, ":", 2)
-
- n := specgen.Namespace{}
- switch {
- case netInput == "bridge":
- n.NSMode = specgen.Bridge
- case netInput == "host":
- n.NSMode = specgen.Host
- case netInput == "slirp4netns", strings.HasPrefix(netInput, "slirp4netns:"):
- n.NSMode = specgen.Slirp
- if len(parts) > 1 {
- createOptions.Net.NetworkOptions = make(map[string][]string)
- createOptions.Net.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
- }
- default:
- // Container and NS mode are presently unsupported
- n.NSMode = specgen.Bridge
- createOptions.Net.CNINetworks = strings.Split(netInput, ",")
- }
- createOptions.Net.Network = n
- }
+
if len(createOptions.Net.PublishPorts) > 0 {
if !createOptions.Infra {
return errors.Errorf("you must have an infra container to publish port bindings to the host")
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 34d92cd0f..7840e6100 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -113,33 +113,9 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
return nil
}
- // Special case if command is hidden completion command ("__complete","__completeNoDesc")
- // Since __completeNoDesc is an alias the cm.Name is always __complete
- if cmd.Name() == cobra.ShellCompRequestCmd {
- // Parse the cli arguments after the the completion cmd (always called as second argument)
- // This ensures that the --url, --identity and --connection flags are properly set
- compCmd, _, err := cmd.Root().Traverse(os.Args[2:])
- if err != nil {
- return err
- }
- // If we don't complete the root cmd hide all root flags
- // so they won't show up in the completions on subcommands.
- if compCmd != compCmd.Root() {
- compCmd.Root().Flags().VisitAll(func(flag *pflag.Flag) {
- flag.Hidden = true
- })
- }
- // No need for further setup when completing commands with subcommands.
- if compCmd.HasSubCommands() {
- requireCleanup = false
- return nil
- }
- }
-
cfg := registry.PodmanConfig()
// --connection is not as "special" as --remote so we can wait and process it here
- var connErr error
conn := cmd.Root().LocalFlags().Lookup("connection")
if conn != nil && conn.Changed {
cfg.Engine.ActiveService = conn.Value.String()
@@ -147,19 +123,37 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
var err error
cfg.URI, cfg.Identity, err = cfg.ActiveDestination()
if err != nil {
- connErr = errors.Wrap(err, "failed to resolve active destination")
+ return errors.Wrap(err, "failed to resolve active destination")
}
if err := cmd.Root().LocalFlags().Set("url", cfg.URI); err != nil {
- connErr = errors.Wrap(err, "failed to override --url flag")
+ return errors.Wrap(err, "failed to override --url flag")
}
if err := cmd.Root().LocalFlags().Set("identity", cfg.Identity); err != nil {
- connErr = errors.Wrap(err, "failed to override --identity flag")
+ return errors.Wrap(err, "failed to override --identity flag")
}
}
- if connErr != nil {
- return connErr
+
+ // Special case if command is hidden completion command ("__complete","__completeNoDesc")
+ // Since __completeNoDesc is an alias the cm.Name is always __complete
+ if cmd.Name() == cobra.ShellCompRequestCmd {
+ // Parse the cli arguments after the the completion cmd (always called as second argument)
+ // This ensures that the --url, --identity and --connection flags are properly set
+ compCmd, _, err := cmd.Root().Traverse(os.Args[2:])
+ if err != nil {
+ return err
+ }
+ // If we don't complete the root cmd hide all root flags
+ // so they won't show up in the completions on subcommands.
+ if compCmd != compCmd.Root() {
+ compCmd.Root().Flags().VisitAll(func(flag *pflag.Flag) {
+ flag.Hidden = true
+ })
+ }
+ // No need for further setup the completion logic setups the engines as needed.
+ requireCleanup = false
+ return nil
}
// Prep the engines
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 8251ba3b6..eb73609d4 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -588,7 +588,7 @@ Valid _mode_ values are:
- **none**: no networking;
- **container:**_id_: reuse another container's network stack;
- **host**: use the Podman host network stack. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure;
-- _network-id_: connect to a user-defined network, multiple networks should be comma separated;
+- **cni-network**: connect to a user-defined network, multiple networks should be comma-separated or they can be specified with multiple uses of the **--network** option;
- **ns:**_path_: path to a network namespace to join;
- **private**: create a new namespace for the container (default)
- **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options:
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index bc3d5a8bb..184c12acd 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -614,7 +614,7 @@ Valid _mode_ values are:
- **none**: no networking;
- **container:**_id_: reuse another container's network stack;
- **host**: use the Podman host network stack. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure;
-- _network-id_: connect to a user-defined network, multiple networks should be comma separated;
+- **cni-network**: connect to a user-defined network, multiple networks should be comma-separated or they can be specified with multiple uses of the **--network** option;
- **ns:**_path_: path to a network namespace to join;
- **private**: create a new namespace for the container (default)
- **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options:
diff --git a/docs/source/markdown/podman-top.1.md b/docs/source/markdown/podman-top.1.md
index f307f96da..cfb89567c 100644
--- a/docs/source/markdown/podman-top.1.md
+++ b/docs/source/markdown/podman-top.1.md
@@ -9,7 +9,7 @@ podman\-top - Display the running processes of a container
**podman container top** [*options*] *container* [*format-descriptors*]
## DESCRIPTION
-Display the running processes of the container. The *format-descriptors* are ps (1) compatible AIX format descriptors but extended to print additional information, such as the seccomp mode or the effective capabilities of a given process. The descriptors can either be passed as separated arguments or as a single comma-separated argument. Note that you can also specify options and or flags of ps(1); in this case, Podman will fallback to executing ps with the specified arguments and flags in the container.
+Display the running processes of the container. The *format-descriptors* are ps (1) compatible AIX format descriptors but extended to print additional information, such as the seccomp mode or the effective capabilities of a given process. The descriptors can either be passed as separated arguments or as a single comma-separated argument. Note that you can also specify options and or flags of ps(1); in this case, Podman will fallback to executing ps with the specified arguments and flags in the container. Please use the "h*" descriptors if you want to extract host-related information. For instance, `podman top $name hpid huser` to display the PID and user of the processes in the host context.
## OPTIONS
diff --git a/libpod/container.go b/libpod/container.go
index 31c958959..e954d84eb 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/lock"
+ "github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -1095,13 +1096,17 @@ func (c *Container) Umask() string {
// values at runtime via network connect and disconnect.
// If the container is configured to use CNI and this function returns an empty
// array, the container will still be connected to the default network.
-func (c *Container) Networks() ([]string, error) {
+// The second return parameter, a bool, indicates that the container container
+// is joining the default CNI network - the network name will be included in the
+// returned array of network names, but the container did not explicitly join
+// this network.
+func (c *Container) Networks() ([]string, bool, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
- return nil, err
+ return nil, false, err
}
}
@@ -1109,19 +1114,22 @@ func (c *Container) Networks() ([]string, error) {
}
// Unlocked accessor for networks
-func (c *Container) networks() ([]string, error) {
+func (c *Container) networks() ([]string, bool, error) {
networks, err := c.runtime.state.GetNetworks(c)
if err != nil && errors.Cause(err) == define.ErrNoSuchNetwork {
- return c.config.Networks, nil
+ if len(c.config.Networks) == 0 && !rootless.IsRootless() {
+ return []string{c.runtime.netPlugin.GetDefaultNetworkName()}, true, nil
+ }
+ return c.config.Networks, false, nil
}
- return networks, err
+ return networks, false, err
}
// networksByNameIndex provides us with a map of container networks where key
// is network name and value is the index position
func (c *Container) networksByNameIndex() (map[string]int, error) {
- networks, err := c.networks()
+ networks, _, err := c.networks()
if err != nil {
return nil, err
}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index ffd0dc92f..b6a3244ea 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -643,18 +643,13 @@ func (c *Container) removeIPv4Allocations() error {
cniDefaultNetwork = c.runtime.netPlugin.GetDefaultNetworkName()
}
- networks, err := c.networks()
+ networks, _, err := c.networks()
if err != nil {
return err
}
- switch {
- case len(networks) > 0 && len(networks) != len(c.state.NetworkStatus):
+ if len(networks) != len(c.state.NetworkStatus) {
return errors.Wrapf(define.ErrInternal, "network mismatch: asked to join %d CNI networks but got %d CNI results", len(networks), len(c.state.NetworkStatus))
- case len(networks) == 0 && len(c.state.NetworkStatus) != 1:
- return errors.Wrapf(define.ErrInternal, "network mismatch: did not specify CNI networks but joined more than one (%d)", len(c.state.NetworkStatus))
- case len(networks) == 0 && cniDefaultNetwork == "":
- return errors.Wrapf(define.ErrInternal, "could not retrieve name of CNI default network")
}
for index, result := range c.state.NetworkStatus {
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 8dce7c9fe..7a0bebd95 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -110,10 +110,15 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
podName := getCNIPodName(ctr)
- networks, err := ctr.networks()
+ networks, _, err := ctr.networks()
if err != nil {
return nil, err
}
+ // All networks have been removed from the container.
+ // This is effectively forcing net=none.
+ if len(networks) == 0 {
+ return nil, nil
+ }
// Update container map of interface descriptions
if err := ctr.setupNetworkDescriptions(networks); err != nil {
@@ -224,7 +229,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
if ctr.config.NetMode.IsSlirp4netns() {
return r.setupSlirp4netns(ctr)
}
- networks, err := ctr.networks()
+ networks, _, err := ctr.networks()
if err != nil {
return err
}
@@ -744,13 +749,13 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
- networks, err := ctr.networks()
+ networks, _, err := ctr.networks()
if err != nil {
return err
}
// rootless containers do not use the CNI plugin directly
- if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
+ if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() && len(networks) > 0 {
var requestedIP net.IP
if ctr.requestedIP != nil {
requestedIP = ctr.requestedIP
@@ -863,7 +868,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
settings := new(define.InspectNetworkSettings)
settings.Ports = makeInspectPortBindings(c.config.PortMappings)
- networks, err := c.networks()
+ networks, isDefault, err := c.networks()
if err != nil {
return nil, err
}
@@ -872,7 +877,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
if c.state.NetNS == nil {
// We still want to make dummy configurations for each CNI net
// the container joined.
- if len(networks) > 0 {
+ if len(networks) > 0 && !isDefault {
settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(networks))
for _, net := range networks {
cniNet := new(define.InspectAdditionalNetwork)
@@ -893,7 +898,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
}
// If we have CNI networks - handle that here
- if len(networks) > 0 {
+ if len(networks) > 0 && !isDefault {
if len(networks) != len(c.state.NetworkStatus) {
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(networks), len(c.state.NetworkStatus))
}
@@ -1101,7 +1106,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
return err
}
- ctrNetworks, err := c.networks()
+ ctrNetworks, _, err := c.networks()
if err != nil {
return err
}
diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go
index 1d6158cc2..2c2977f9f 100644
--- a/libpod/rootless_cni_linux.go
+++ b/libpod/rootless_cni_linux.go
@@ -40,7 +40,7 @@ const (
//
// AllocRootlessCNI does not lock c. c should be already locked.
func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.Result, error) {
- networks, err := c.networks()
+ networks, _, err := c.networks()
if err != nil {
return nil, nil, err
}
@@ -81,7 +81,7 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.
//
// DeallocRootlessCNI does not lock c. c should be already locked.
func DeallocRootlessCNI(ctx context.Context, c *Container) error {
- networks, err := c.networks()
+ networks, _, err := c.networks()
if err != nil {
return err
}
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 00be8e845..0ee96b855 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -298,6 +298,9 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
state.Running = true
}
+ formatCapabilities(inspect.HostConfig.CapDrop)
+ formatCapabilities(inspect.HostConfig.CapAdd)
+
h, err := json.Marshal(inspect.HostConfig)
if err != nil {
return nil, err
@@ -428,3 +431,9 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
}
return &c, nil
}
+
+func formatCapabilities(slice []string) {
+ for i := range slice {
+ slice[i] = strings.TrimPrefix(slice[i], "CAP_")
+ }
+}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 101542a98..cbd6e9192 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -51,10 +51,10 @@ func (i *Image) Id() string { // nolint
}
type ImageSummary struct {
- ID string `json:"Id"`
- ParentId string `json:",omitempty"` // nolint
- RepoTags []string `json:",omitempty"`
- Created int64 `json:",omitempty"`
+ ID string `json:"Id"`
+ ParentId string `json:",omitempty"` // nolint
+ RepoTags []string `json:",omitempty"`
+ Created int64
Size int64 `json:",omitempty"`
SharedSize int `json:",omitempty"`
VirtualSize int64 `json:",omitempty"`
diff --git a/pkg/specgen/namespaces.go b/pkg/specgen/namespaces.go
index 90c56d366..11108a5c1 100644
--- a/pkg/specgen/namespaces.go
+++ b/pkg/specgen/namespaces.go
@@ -272,16 +272,10 @@ func ParseNetworkNamespace(ns string) (Namespace, []string, error) {
toReturn.NSMode = Private
case strings.HasPrefix(ns, "ns:"):
split := strings.SplitN(ns, ":", 2)
- if len(split) != 2 {
- return toReturn, nil, errors.Errorf("must provide a path to a namespace when specifying ns:")
- }
toReturn.NSMode = Path
toReturn.Value = split[1]
case strings.HasPrefix(ns, "container:"):
split := strings.SplitN(ns, ":", 2)
- if len(split) != 2 {
- return toReturn, nil, errors.Errorf("must provide name or ID or a container when specifying container:")
- }
toReturn.NSMode = FromContainer
toReturn.Value = split[1]
default:
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index be0a2f6f0..ccfbcefae 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
. "github.com/containers/podman/v2/test/utils"
+ "github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
@@ -476,4 +477,23 @@ entrypoint ["/fromimage"]
Expect(status3.ExitCode()).To(Equal(0))
Expect(strings.Contains(status3.OutputToString(), "Degraded")).To(BeTrue())
})
+
+ It("podman create pod invalid network config", func() {
+ net1 := "n1" + stringid.GenerateNonCryptoID()
+ session := podmanTest.Podman([]string{"network", "create", net1})
+ session.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(net1)
+ Expect(session.ExitCode()).To(BeZero())
+
+ session = podmanTest.Podman([]string{"pod", "create", "--network", "host", "--network", net1})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ Expect(session.ErrorToString()).To(ContainSubstring("host"))
+ Expect(session.ErrorToString()).To(ContainSubstring("bridge"))
+
+ session = podmanTest.Podman([]string{"pod", "create", "--network", "container:abc"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ Expect(session.ErrorToString()).To(ContainSubstring("pods presently do not support network mode container"))
+ })
})
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index 3e80e953e..1d416498c 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -665,4 +665,33 @@ var _ = Describe("Podman run networking", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(BeZero())
})
+
+ It("podman run with multiple networks", func() {
+ net1 := "n1" + stringid.GenerateNonCryptoID()
+ session := podmanTest.Podman([]string{"network", "create", net1})
+ session.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(net1)
+ Expect(session.ExitCode()).To(BeZero())
+
+ net2 := "n2" + stringid.GenerateNonCryptoID()
+ session = podmanTest.Podman([]string{"network", "create", net2})
+ session.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(net2)
+ Expect(session.ExitCode()).To(BeZero())
+
+ run := podmanTest.Podman([]string{"run", "--network", net1, "--network", net2, ALPINE, "ip", "-o", "-4", "addr"})
+ run.WaitWithDefaultTimeout()
+ Expect(run.ExitCode()).To(BeZero())
+ Expect(len(run.OutputToStringArray())).To(Equal(3))
+ Expect(run.OutputToString()).To(ContainSubstring("lo"))
+ Expect(run.OutputToString()).To(ContainSubstring("eth0"))
+ Expect(run.OutputToString()).To(ContainSubstring("eth1"))
+
+ //invalid config network host and cni should fail
+ run = podmanTest.Podman([]string{"run", "--network", "host", "--network", net2, ALPINE, "ip", "-o", "-4", "addr"})
+ run.WaitWithDefaultTimeout()
+ Expect(run.ExitCode()).To(Equal(125))
+ Expect(run.ErrorToString()).To(ContainSubstring("host"))
+ Expect(run.ErrorToString()).To(ContainSubstring("bridge"))
+ })
})