summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/attach.go2
-rw-r--r--cmd/podman/build.go2
-rw-r--r--cmd/podman/checkpoint.go2
-rw-r--r--cmd/podman/cleanup.go2
-rw-r--r--cmd/podman/commit.go2
-rw-r--r--cmd/podman/common.go12
-rw-r--r--cmd/podman/create.go2
-rw-r--r--cmd/podman/diff.go2
-rw-r--r--cmd/podman/exec.go2
-rw-r--r--cmd/podman/export.go2
-rw-r--r--cmd/podman/history.go2
-rw-r--r--cmd/podman/images.go2
-rw-r--r--cmd/podman/import.go2
-rw-r--r--cmd/podman/info.go2
-rw-r--r--cmd/podman/inspect.go2
-rw-r--r--cmd/podman/kill.go2
-rw-r--r--cmd/podman/load.go2
-rw-r--r--cmd/podman/login.go2
-rw-r--r--cmd/podman/logout.go2
-rw-r--r--cmd/podman/logs.go2
-rw-r--r--cmd/podman/mount.go2
-rw-r--r--cmd/podman/pod_create.go2
-rw-r--r--cmd/podman/pod_inspect.go2
-rw-r--r--cmd/podman/pod_kill.go2
-rw-r--r--cmd/podman/pod_pause.go2
-rw-r--r--cmd/podman/pod_ps.go2
-rw-r--r--cmd/podman/pod_restart.go2
-rw-r--r--cmd/podman/pod_rm.go2
-rw-r--r--cmd/podman/pod_start.go2
-rw-r--r--cmd/podman/pod_stats.go2
-rw-r--r--cmd/podman/pod_stop.go2
-rw-r--r--cmd/podman/pod_top.go2
-rw-r--r--cmd/podman/pod_unpause.go2
-rw-r--r--cmd/podman/port.go2
-rw-r--r--cmd/podman/ps.go2
-rw-r--r--cmd/podman/pull.go2
-rw-r--r--cmd/podman/push.go2
-rw-r--r--cmd/podman/refresh.go2
-rw-r--r--cmd/podman/restart.go2
-rw-r--r--cmd/podman/restore.go2
-rw-r--r--cmd/podman/rm.go2
-rw-r--r--cmd/podman/rmi.go2
-rw-r--r--cmd/podman/run.go2
-rw-r--r--cmd/podman/run_test.go2
-rw-r--r--cmd/podman/runlabel.go2
-rw-r--r--cmd/podman/save.go2
-rw-r--r--cmd/podman/search.go2
-rw-r--r--cmd/podman/start.go2
-rw-r--r--cmd/podman/stats.go2
-rw-r--r--cmd/podman/stop.go29
-rw-r--r--cmd/podman/top.go2
-rw-r--r--cmd/podman/umount.go2
-rw-r--r--cmd/podman/utils.go48
-rw-r--r--cmd/podman/varlink.go2
-rw-r--r--cmd/podman/wait.go2
-rw-r--r--completions/bash/podman1
-rw-r--r--docs/podman-create.1.md6
-rw-r--r--docs/podman-run.1.md6
-rw-r--r--libpod/boltdb_state_linux.go2
-rw-r--r--libpod/container.go8
-rw-r--r--libpod/container_easyjson.go14
-rw-r--r--libpod/networking_linux.go19
-rw-r--r--libpod/options.go25
-rw-r--r--libpod/pod_easyjson.go2
-rw-r--r--pkg/rootless/rootless_linux.c92
-rw-r--r--pkg/spec/createconfig.go13
-rw-r--r--test/e2e/run_staticip_test.go58
-rw-r--r--vendor.conf3
-rw-r--r--vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go41
-rw-r--r--vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go17
70 files changed, 404 insertions, 96 deletions
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index 5b58c022a..dc0563a94 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -30,7 +30,7 @@ var (
Name: "attach",
Usage: "Attach to a running container",
Description: attachDescription,
- Flags: attachFlags,
+ Flags: sortFlags(attachFlags),
Action: attachCmd,
ArgsUsage: "",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 1b8a5faec..424f9d471 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -29,7 +29,7 @@ var (
Name: "build",
Usage: "Build an image using instructions from Dockerfiles",
Description: buildDescription,
- Flags: append(append(buildahcli.BudFlags, layerFlags...), buildahcli.FromAndBudFlags...),
+ Flags: sortFlags(append(append(buildahcli.BudFlags, layerFlags...), buildahcli.FromAndBudFlags...)),
Action: buildCmd,
ArgsUsage: "CONTEXT-DIRECTORY | URL",
SkipArgReorder: true,
diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go
index cbbbcd740..8582ce138 100644
--- a/cmd/podman/checkpoint.go
+++ b/cmd/podman/checkpoint.go
@@ -27,7 +27,7 @@ var (
Name: "checkpoint",
Usage: "Checkpoints one or more containers",
Description: checkpointDescription,
- Flags: checkpointFlags,
+ Flags: sortFlags(checkpointFlags),
Action: checkpointCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
}
diff --git a/cmd/podman/cleanup.go b/cmd/podman/cleanup.go
index 316704f91..3fd150783 100644
--- a/cmd/podman/cleanup.go
+++ b/cmd/podman/cleanup.go
@@ -27,7 +27,7 @@ var (
Name: "cleanup",
Usage: "Cleanup network and mountpoints of one or more containers",
Description: cleanupDescription,
- Flags: cleanupFlags,
+ Flags: sortFlags(cleanupFlags),
Action: cleanupCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go
index 234926de0..b09c6b0d9 100644
--- a/cmd/podman/commit.go
+++ b/cmd/podman/commit.go
@@ -52,7 +52,7 @@ var (
Name: "commit",
Usage: "Create new image based on the changed container",
Description: commitDescription,
- Flags: commitFlags,
+ Flags: sortFlags(commitFlags),
Action: commitCmd,
ArgsUsage: "CONTAINER [REPOSITORY[:TAG]]",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 9ab0e57e5..1e7f8d4d8 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -6,6 +6,7 @@ import (
"os"
"reflect"
"regexp"
+ "sort"
"strings"
"github.com/containers/buildah"
@@ -249,6 +250,10 @@ var createFlags = []cli.Flag{
Usage: "Keep STDIN open even if not attached",
},
cli.StringFlag{
+ Name: "ip",
+ Usage: "Specify a static IPv4 address for the container",
+ },
+ cli.StringFlag{
Name: "ipc",
Usage: "IPC namespace to use",
},
@@ -446,3 +451,10 @@ func getFormat(c *cli.Context) (string, error) {
}
return "", errors.Errorf("unrecognized image type %q", format)
}
+
+func sortFlags(flags []cli.Flag) []cli.Flag {
+ sort.Slice(flags, func(i, j int) bool {
+ return strings.Compare(flags[i].GetName(), flags[j].GetName()) < 0
+ })
+ return flags
+}
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index e442e5c03..248ff1b7d 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -48,7 +48,7 @@ var createCommand = cli.Command{
Name: "create",
Usage: "Create but do not start a container",
Description: createDescription,
- Flags: createFlags,
+ Flags: sortFlags(createFlags),
Action: createCmd,
ArgsUsage: "IMAGE [COMMAND [ARG...]]",
HideHelp: true,
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index dc35ea5a3..5f813699f 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -51,7 +51,7 @@ var (
Name: "diff",
Usage: "Inspect changes on container's file systems",
Description: diffDescription,
- Flags: diffFlags,
+ Flags: sortFlags(diffFlags),
Action: diffCmd,
ArgsUsage: "ID-NAME",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index 38cee67d6..1dcb88dbd 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -46,7 +46,7 @@ var (
Name: "exec",
Usage: "Run a process in a running container",
Description: execDescription,
- Flags: execFlags,
+ Flags: sortFlags(execFlags),
Action: execCmd,
ArgsUsage: "CONTAINER-NAME",
SkipArgReorder: true,
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index dd73c8663..667b8d012 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -23,7 +23,7 @@ var (
Name: "export",
Usage: "Export container's filesystem contents as a tar archive",
Description: exportDescription,
- Flags: exportFlags,
+ Flags: sortFlags(exportFlags),
Action: exportCmd,
ArgsUsage: "CONTAINER",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/history.go b/cmd/podman/history.go
index 35f71dc60..7c8c619c8 100644
--- a/cmd/podman/history.go
+++ b/cmd/podman/history.go
@@ -59,7 +59,7 @@ var (
Name: "history",
Usage: "Show history of a specified image",
Description: historyDescription,
- Flags: historyFlags,
+ Flags: sortFlags(historyFlags),
Action: historyCmd,
ArgsUsage: "",
UseShortOptionHandling: true,
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index f88ca32fd..a8955e49e 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -124,7 +124,7 @@ var (
Name: "images",
Usage: "List images in local storage",
Description: imagesDescription,
- Flags: imagesFlags,
+ Flags: sortFlags(imagesFlags),
Action: imagesCmd,
ArgsUsage: "",
UseShortOptionHandling: true,
diff --git a/cmd/podman/import.go b/cmd/podman/import.go
index c663e7128..be516e4fa 100644
--- a/cmd/podman/import.go
+++ b/cmd/podman/import.go
@@ -39,7 +39,7 @@ var (
Name: "import",
Usage: "Import a tarball to create a filesystem image",
Description: importDescription,
- Flags: importFlags,
+ Flags: sortFlags(importFlags),
Action: importCmd,
ArgsUsage: "TARBALL [REFERENCE]",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index 927bf57be..563e63ba3 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -16,7 +16,7 @@ var (
Name: "info",
Usage: infoDescription,
Description: `Information display here pertain to the host, current storage stats, and build of podman. Useful for the user and when reporting issues.`,
- Flags: infoFlags,
+ Flags: sortFlags(infoFlags),
Action: infoCmd,
ArgsUsage: "",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index f4c460777..bd9e8c13c 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -41,7 +41,7 @@ var (
Name: "inspect",
Usage: "Displays the configuration of a container or image",
Description: inspectDescription,
- Flags: inspectFlags,
+ Flags: sortFlags(inspectFlags),
Action: inspectCmd,
ArgsUsage: "CONTAINER-OR-IMAGE [CONTAINER-OR-IMAGE]...",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go
index db3300984..56dd170b5 100644
--- a/cmd/podman/kill.go
+++ b/cmd/podman/kill.go
@@ -31,7 +31,7 @@ var (
Name: "kill",
Usage: "Kill one or more running containers with a specific signal",
Description: killDescription,
- Flags: killFlags,
+ Flags: sortFlags(killFlags),
Action: killCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/load.go b/cmd/podman/load.go
index 4dc5c1e3a..f39ee4487 100644
--- a/cmd/podman/load.go
+++ b/cmd/podman/load.go
@@ -36,7 +36,7 @@ var (
Name: "load",
Usage: "Load an image from docker archive",
Description: loadDescription,
- Flags: loadFlags,
+ Flags: sortFlags(loadFlags),
Action: loadCmd,
ArgsUsage: "",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index afbd180f8..8625828de 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -43,7 +43,7 @@ var (
Name: "login",
Usage: "Login to a container registry",
Description: loginDescription,
- Flags: loginFlags,
+ Flags: sortFlags(loginFlags),
Action: loginCmd,
ArgsUsage: "REGISTRY",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go
index fa77df2ab..d2a2da790 100644
--- a/cmd/podman/logout.go
+++ b/cmd/podman/logout.go
@@ -25,7 +25,7 @@ var (
Name: "logout",
Usage: "Logout of a container registry",
Description: logoutDescription,
- Flags: logoutFlags,
+ Flags: sortFlags(logoutFlags),
Action: logoutCmd,
ArgsUsage: "REGISTRY",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go
index 34d062c56..84aca5e61 100644
--- a/cmd/podman/logs.go
+++ b/cmd/podman/logs.go
@@ -43,7 +43,7 @@ var (
Name: "logs",
Usage: "Fetch the logs of a container",
Description: logsDescription,
- Flags: logsFlags,
+ Flags: sortFlags(logsFlags),
Action: logsCmd,
ArgsUsage: "CONTAINER",
SkipArgReorder: true,
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index fbaf2baf1..585f506cd 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -36,7 +36,7 @@ var (
Description: mountDescription,
Action: mountCmd,
ArgsUsage: "[CONTAINER-NAME-OR-ID [...]]",
- Flags: mountFlags,
+ Flags: sortFlags(mountFlags),
OnUsageError: usageErrorHandler,
}
)
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 61086f890..c3a45a093 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -69,7 +69,7 @@ var podCreateCommand = cli.Command{
Name: "create",
Usage: "Create a new empty pod",
Description: podCreateDescription,
- Flags: podCreateFlags,
+ Flags: sortFlags(podCreateFlags),
Action: podCreateCmd,
SkipArgReorder: true,
UseShortOptionHandling: true,
diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go
index 34208336b..77178b14d 100644
--- a/cmd/podman/pod_inspect.go
+++ b/cmd/podman/pod_inspect.go
@@ -19,7 +19,7 @@ var (
Name: "inspect",
Usage: "displays a pod configuration",
Description: podInspectDescription,
- Flags: podInspectFlags,
+ Flags: sortFlags(podInspectFlags),
Action: podInspectCmd,
UseShortOptionHandling: true,
ArgsUsage: "[POD_NAME_OR_ID]",
diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go
index 11a3a9207..c8029eb46 100644
--- a/cmd/podman/pod_kill.go
+++ b/cmd/podman/pod_kill.go
@@ -29,7 +29,7 @@ var (
Name: "kill",
Usage: "Send the specified signal or SIGKILL to containers in pod",
Description: podKillDescription,
- Flags: podKillFlags,
+ Flags: sortFlags(podKillFlags),
Action: podKillCmd,
ArgsUsage: "[POD_NAME_OR_ID]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go
index 9eb80cddf..e8de0debc 100644
--- a/cmd/podman/pod_pause.go
+++ b/cmd/podman/pod_pause.go
@@ -25,7 +25,7 @@ var (
Name: "pause",
Usage: "Pause one or more pods",
Description: podPauseDescription,
- Flags: podPauseFlags,
+ Flags: sortFlags(podPauseFlags),
Action: podPauseCmd,
ArgsUsage: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go
index 85d4e51e2..2030b9b04 100644
--- a/cmd/podman/pod_ps.go
+++ b/cmd/podman/pod_ps.go
@@ -161,7 +161,7 @@ var (
Aliases: []string{"ls", "list"},
Usage: "List pods",
Description: podPsDescription,
- Flags: podPsFlags,
+ Flags: sortFlags(podPsFlags),
Action: podPsCmd,
UseShortOptionHandling: true,
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go
index b4a7f9e10..e956b2f70 100644
--- a/cmd/podman/pod_restart.go
+++ b/cmd/podman/pod_restart.go
@@ -23,7 +23,7 @@ var (
Name: "restart",
Usage: "Restart one or more pods",
Description: podRestartDescription,
- Flags: podRestartFlags,
+ Flags: sortFlags(podRestartFlags),
Action: podRestartCmd,
ArgsUsage: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index 09eb9b394..49f2104cf 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -30,7 +30,7 @@ If --force is specified, all containers will be stopped, then removed.
Name: "rm",
Usage: "Remove one or more pods",
Description: podRmDescription,
- Flags: podRmFlags,
+ Flags: sortFlags(podRmFlags),
Action: podRmCmd,
ArgsUsage: "[POD ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go
index 4735028e0..f0a7926c9 100644
--- a/cmd/podman/pod_start.go
+++ b/cmd/podman/pod_start.go
@@ -27,7 +27,7 @@ var (
Name: "start",
Usage: "Start one or more pods",
Description: podStartDescription,
- Flags: podStartFlags,
+ Flags: sortFlags(podStartFlags),
Action: podStartCmd,
ArgsUsage: "POD-NAME [POD-NAME ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 0a3c6942b..2e29445b4 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -39,7 +39,7 @@ var (
Name: "stats",
Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for containers in one or more pods",
Description: podStatsDescription,
- Flags: podStatsFlags,
+ Flags: sortFlags(podStatsFlags),
Action: podStatsCmd,
ArgsUsage: "[POD_NAME_OR_ID]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index 6dc6a2b2d..14114aa11 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -27,7 +27,7 @@ var (
Name: "stop",
Usage: "Stop one or more pods",
Description: podStopDescription,
- Flags: podStopFlags,
+ Flags: sortFlags(podStopFlags),
Action: podStopCmd,
ArgsUsage: "POD-NAME [POD-NAME ...]",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go
index fe351c707..1bd1287db 100644
--- a/cmd/podman/pod_top.go
+++ b/cmd/podman/pod_top.go
@@ -32,7 +32,7 @@ the latest pod.
Name: "top",
Usage: "Display the running processes of containers in a pod",
Description: podTopDescription,
- Flags: podTopFlags,
+ Flags: sortFlags(podTopFlags),
Action: podTopCmd,
ArgsUsage: "POD-NAME [format descriptors]",
SkipArgReorder: true,
diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go
index cdee3cbe7..5256f680c 100644
--- a/cmd/podman/pod_unpause.go
+++ b/cmd/podman/pod_unpause.go
@@ -25,7 +25,7 @@ var (
Name: "unpause",
Usage: "Unpause one or more pods",
Description: podUnpauseDescription,
- Flags: podUnpauseFlags,
+ Flags: sortFlags(podUnpauseFlags),
Action: podUnpauseCmd,
ArgsUsage: "POD-NAME|POD-ID [POD-NAME|POD-ID ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/port.go b/cmd/podman/port.go
index b7c88887a..d6497d450 100644
--- a/cmd/podman/port.go
+++ b/cmd/podman/port.go
@@ -29,7 +29,7 @@ var (
Name: "port",
Usage: "List port mappings or a specific mapping for the container",
Description: portDescription,
- Flags: portFlags,
+ Flags: sortFlags(portFlags),
Action: portCmd,
ArgsUsage: "CONTAINER-NAME [mapping]",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index e53afe1bf..32b3a0574 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -182,7 +182,7 @@ var (
Name: "ps",
Usage: "List containers",
Description: psDescription,
- Flags: psFlags,
+ Flags: sortFlags(psFlags),
Action: psCmd,
ArgsUsage: "",
UseShortOptionHandling: true,
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 902bd867c..097c88536 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -54,7 +54,7 @@ specified, the image with the 'latest' tag (if it exists) is pulled
Name: "pull",
Usage: "Pull an image from a registry",
Description: pullDescription,
- Flags: pullFlags,
+ Flags: sortFlags(pullFlags),
Action: pullCmd,
ArgsUsage: "",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index d9aa2246b..9f2f41835 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -70,7 +70,7 @@ var (
Name: "push",
Usage: "Push an image to a specified destination",
Description: pushDescription,
- Flags: pushFlags,
+ Flags: sortFlags(pushFlags),
Action: pushCmd,
ArgsUsage: "IMAGE DESTINATION",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go
index df16ad5f0..b07376170 100644
--- a/cmd/podman/refresh.go
+++ b/cmd/podman/refresh.go
@@ -18,7 +18,7 @@ var (
Name: "refresh",
Usage: "Refresh container state",
Description: refreshDescription,
- Flags: refreshFlags,
+ Flags: sortFlags(refreshFlags),
Action: refreshCmd,
UseShortOptionHandling: true,
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go
index d2d0c0fd7..7b48ef24e 100644
--- a/cmd/podman/restart.go
+++ b/cmd/podman/restart.go
@@ -26,7 +26,7 @@ var (
Name: "restart",
Usage: "Restart one or more containers",
Description: restartDescription,
- Flags: restartFlags,
+ Flags: sortFlags(restartFlags),
Action: restartCmd,
ArgsUsage: "CONTAINER [CONTAINER ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go
index 43ef87ca2..623c4936e 100644
--- a/cmd/podman/restore.go
+++ b/cmd/podman/restore.go
@@ -27,7 +27,7 @@ var (
Name: "restore",
Usage: "Restores one or more containers from a checkpoint",
Description: restoreDescription,
- Flags: restoreFlags,
+ Flags: sortFlags(restoreFlags),
Action: restoreCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
}
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index caf7a5f36..f64eca6f4 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -35,7 +35,7 @@ Running containers will not be removed without the -f option.
Name: "rm",
Usage: "Remove one or more containers",
Description: rmDescription,
- Flags: rmFlags,
+ Flags: sortFlags(rmFlags),
Action: rmCmd,
ArgsUsage: "",
UseShortOptionHandling: true,
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index fdeab6b80..c0a0d69df 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -29,7 +29,7 @@ var (
Description: rmiDescription,
Action: rmiCmd,
ArgsUsage: "IMAGE-NAME-OR-ID [...]",
- Flags: rmiFlags,
+ Flags: sortFlags(rmiFlags),
UseShortOptionHandling: true,
OnUsageError: usageErrorHandler,
}
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index fbad4237d..e4b25eaf4 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -27,7 +27,7 @@ var runCommand = cli.Command{
Name: "run",
Usage: "Run a command in a new container",
Description: runDescription,
- Flags: runFlags,
+ Flags: sortFlags(runFlags),
Action: runCmd,
ArgsUsage: "IMAGE [COMMAND [ARG...]]",
HideHelp: true,
diff --git a/cmd/podman/run_test.go b/cmd/podman/run_test.go
index 0a79f6ec3..079e570aa 100644
--- a/cmd/podman/run_test.go
+++ b/cmd/podman/run_test.go
@@ -18,7 +18,7 @@ var (
CLI *cli.Context
testCommand = cli.Command{
Name: "test",
- Flags: createFlags,
+ Flags: sortFlags(createFlags),
Action: testCmd,
HideHelp: true,
}
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index d514a79fc..2d464b949 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -79,7 +79,7 @@ Executes a command as described by a container image label.
Name: "runlabel",
Usage: "Execute the command described by an image label",
Description: runlabelDescription,
- Flags: runlabelFlags,
+ Flags: sortFlags(runlabelFlags),
Action: runlabelCmd,
ArgsUsage: "",
SkipArgReorder: true,
diff --git a/cmd/podman/save.go b/cmd/podman/save.go
index a1e980f34..7edc42e0d 100644
--- a/cmd/podman/save.go
+++ b/cmd/podman/save.go
@@ -53,7 +53,7 @@ var (
Name: "save",
Usage: "Save image to an archive",
Description: saveDescription,
- Flags: saveFlags,
+ Flags: sortFlags(saveFlags),
Action: saveCmd,
ArgsUsage: "",
SkipArgReorder: true,
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index f64b822fc..49b1b7f7b 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -55,7 +55,7 @@ var (
Name: "search",
Usage: "Search registry for image",
Description: searchDescription,
- Flags: searchFlags,
+ Flags: sortFlags(searchFlags),
Action: searchCmd,
ArgsUsage: "TERM",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index a34f6df5d..8cf85405e 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -41,7 +41,7 @@ var (
Name: "start",
Usage: "Start one or more containers",
Description: startDescription,
- Flags: startFlags,
+ Flags: sortFlags(startFlags),
Action: startCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
UseShortOptionHandling: true,
diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go
index 0e1d2a9c6..dea351e88 100644
--- a/cmd/podman/stats.go
+++ b/cmd/podman/stats.go
@@ -52,7 +52,7 @@ var (
Name: "stats",
Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers",
Description: statsDescription,
- Flags: statsFlags,
+ Flags: sortFlags(statsFlags),
Action: statsCmd,
ArgsUsage: "",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go
index d2fa87730..ff0b36bf1 100644
--- a/cmd/podman/stop.go
+++ b/cmd/podman/stop.go
@@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
+ rt "runtime"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
@@ -35,7 +36,7 @@ var (
Name: "stop",
Usage: "Stop one or more containers",
Description: stopDescription,
- Flags: stopFlags,
+ Flags: sortFlags(stopFlags),
Action: stopCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
OnUsageError: usageErrorHandler,
@@ -98,21 +99,33 @@ func stopCmd(c *cli.Context) error {
}
}
+ var stopFuncs []workerInput
for _, ctr := range containers {
+ con := ctr
var stopTimeout uint
if c.IsSet("timeout") {
stopTimeout = c.Uint("timeout")
} else {
stopTimeout = ctr.StopTimeout()
}
- if err := ctr.StopWithTimeout(stopTimeout); err != nil && err != libpod.ErrCtrStopped {
- if lastError != nil {
- fmt.Fprintln(os.Stderr, lastError)
- }
- lastError = errors.Wrapf(err, "failed to stop container %v", ctr.ID())
- } else {
- fmt.Println(ctr.ID())
+ f := func() error {
+ return con.StopWithTimeout(stopTimeout)
+ }
+ stopFuncs = append(stopFuncs, workerInput{
+ containerID: con.ID(),
+ parallelFunc: f,
+ })
+ }
+
+ stopErrors := parallelExecuteWorkerPool(rt.NumCPU()*3, stopFuncs)
+
+ for cid, result := range stopErrors {
+ if result != nil && result != libpod.ErrCtrStopped {
+ fmt.Println(result.Error())
+ lastError = result
+ continue
}
+ fmt.Println(cid)
}
return lastError
}
diff --git a/cmd/podman/top.go b/cmd/podman/top.go
index 9b5c3afae..3012265ea 100644
--- a/cmd/podman/top.go
+++ b/cmd/podman/top.go
@@ -42,7 +42,7 @@ the latest container.
Name: "top",
Usage: "Display the running processes of a container",
Description: topDescription,
- Flags: topFlags,
+ Flags: sortFlags(topFlags),
Action: topCmd,
ArgsUsage: "CONTAINER-NAME [format descriptors]",
SkipArgReorder: true,
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index b6837fb5b..24f0f178b 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -35,7 +35,7 @@ An unmount can be forced with the --force flag.
Aliases: []string{"unmount"},
Usage: "Unmounts working container's root filesystem",
Description: description,
- Flags: umountFlags,
+ Flags: sortFlags(umountFlags),
Action: umountCmd,
ArgsUsage: "CONTAINER-NAME-OR-ID",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go
index 89ec48dbe..1b767532e 100644
--- a/cmd/podman/utils.go
+++ b/cmd/podman/utils.go
@@ -5,6 +5,7 @@ import (
"fmt"
"os"
gosignal "os/signal"
+ "sync"
"github.com/containers/libpod/libpod"
"github.com/docker/docker/pkg/signal"
@@ -215,3 +216,50 @@ func getPodsFromContext(c *cli.Context, r *libpod.Runtime) ([]*libpod.Pod, error
}
return pods, lastError
}
+
+type pFunc func() error
+
+type workerInput struct {
+ containerID string
+ parallelFunc pFunc
+}
+
+// worker is a "threaded" worker that takes jobs from the channel "queue"
+func worker(wg *sync.WaitGroup, jobs <-chan workerInput, results map[string]error) {
+ for j := range jobs {
+ err := j.parallelFunc()
+ results[j.containerID] = err
+ wg.Done()
+ }
+}
+
+// parallelExecuteWorkerPool takes container jobs and performs them in parallel. The worker
+// int is determines how many workers/threads should be premade.
+func parallelExecuteWorkerPool(workers int, functions []workerInput) map[string]error {
+ var (
+ wg sync.WaitGroup
+ )
+ results := make(map[string]error)
+ paraJobs := make(chan workerInput, len(functions))
+
+ // If we have more workers than functions, match up the number of workers and functions
+ if workers > len(functions) {
+ workers = len(functions)
+ }
+
+ // Create the workers
+ for w := 1; w <= workers; w++ {
+ go worker(&wg, paraJobs, results)
+ }
+
+ // Add jobs to the workers
+ for _, j := range functions {
+ j := j
+ wg.Add(1)
+ paraJobs <- j
+ }
+
+ close(paraJobs)
+ wg.Wait()
+ return results
+}
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index 2f92d9adb..a7c195041 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -32,7 +32,7 @@ var (
Name: "varlink",
Usage: "Run varlink interface",
Description: varlinkDescription,
- Flags: varlinkFlags,
+ Flags: sortFlags(varlinkFlags),
Action: varlinkCmd,
ArgsUsage: "VARLINK_URI",
OnUsageError: usageErrorHandler,
diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go
index 07db20eee..35ad7a662 100644
--- a/cmd/podman/wait.go
+++ b/cmd/podman/wait.go
@@ -28,7 +28,7 @@ var (
Name: "wait",
Usage: "Block on one or more containers",
Description: waitDescription,
- Flags: waitFlags,
+ Flags: sortFlags(waitFlags),
Action: waitCmd,
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
OnUsageError: usageErrorHandler,
diff --git a/completions/bash/podman b/completions/bash/podman
index 604a25f5d..5cfed348f 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1512,6 +1512,7 @@ _podman_container_run() {
--hostname -h
--image-volume
--init-path
+ --ip
--ipc
--kernel-memory
--label-file
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index c42671b76..509d8820f 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -286,7 +286,9 @@ Not implemented
**--ip**=""
-Not implemented
+Specify a static IP address for the container, for example '10.88.64.128'.
+Can only be used if no additional CNI networks to join were specified via '--network=<network-name>', and if the container is not joining another container's network namespace via '--network=container:<name|id>'.
+The address must be within the default CNI network's pool (default 10.88.0.0/16).
**--ipc**=""
@@ -416,7 +418,7 @@ to the container with **--name** then the daemon will also generate a random
string name. The name is useful any place you need to identify a container.
This works for both background and foreground containers.
-**--network**="*bridge*"
+**--net**, **--network**="*bridge*"
Set the Network mode for the container
'bridge': create a network stack on the default bridge
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index fccebb7f7..c303492e7 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -297,7 +297,9 @@ Not implemented
**--ip**=""
-Not implemented
+Specify a static IP address for the container, for example '10.88.64.128'.
+Can only be used if no additional CNI networks to join were specified via '--network=<network-name>', and if the container is not joining another container's network namespace via '--network=container:<name|id>'.
+The address must be within the default CNI network's pool (default 10.88.0.0/16).
**--ipc**=""
@@ -401,7 +403,7 @@ to the container with **--name** then the daemon will also generate a random
string name. The name is useful any place you need to identify a container.
This works for both background and foreground containers.
-**--network**="*bridge*"
+**--net**, **--network**="*bridge*"
Set the Network mode for the container:
- `bridge`: create a network stack on the default bridge
diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go
index fce3a1b1e..d91f311e5 100644
--- a/libpod/boltdb_state_linux.go
+++ b/libpod/boltdb_state_linux.go
@@ -25,7 +25,7 @@ func replaceNetNS(netNSPath string, ctr *Container, newState *containerState) er
if err == nil {
newState.NetNS = ns
} else {
- logrus.Errorf("error joining network namespace for container %s", ctr.ID())
+ logrus.Errorf("error joining network namespace for container %s: %v", ctr.ID(), err)
ctr.valid = false
}
}
diff --git a/libpod/container.go b/libpod/container.go
index 55a0f3a2c..5997c0b66 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -269,9 +269,13 @@ type ContainerConfig struct {
// Network Config
// CreateNetNS indicates that libpod should create and configure a new
- // network namespace for the container
- // This cannot be set if NetNsCtr is also set
+ // network namespace for the container.
+ // This cannot be set if NetNsCtr is also set.
CreateNetNS bool `json:"createNetNS"`
+ // StaticIP is a static IP to request for the container.
+ // This cannot be set unless CreateNetNS is set.
+ // If not set, the container will be dynamically assigned an IP by CNI.
+ StaticIP net.IP `json:"staticIP"`
// PortMappings are the ports forwarded to the container's network
// namespace
// These are not used unless CreateNetNS is true
diff --git a/libpod/container_easyjson.go b/libpod/container_easyjson.go
index 916118aec..f78366065 100644
--- a/libpod/container_easyjson.go
+++ b/libpod/container_easyjson.go
@@ -1383,6 +1383,10 @@ func easyjson1dbef17bDecodeGithubComContainersLibpodLibpod2(in *jlexer.Lexer, ou
}
case "createNetNS":
out.CreateNetNS = bool(in.Bool())
+ case "staticIP":
+ if data := in.UnsafeBytes(); in.Ok() {
+ in.AddError((out.StaticIP).UnmarshalText(data))
+ }
case "portMappings":
if in.IsNull() {
in.Skip()
@@ -2005,6 +2009,16 @@ func easyjson1dbef17bEncodeGithubComContainersLibpodLibpod2(out *jwriter.Writer,
}
out.Bool(bool(in.CreateNetNS))
}
+ {
+ const prefix string = ",\"staticIP\":"
+ if first {
+ first = false
+ out.RawString(prefix[1:])
+ } else {
+ out.RawString(prefix)
+ }
+ out.RawText((in.StaticIP).MarshalText())
+ }
if len(in.PortMappings) != 0 {
const prefix string = ",\"portMappings\":"
if first {
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 17e79aa62..acb4e2a90 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -5,6 +5,7 @@ package libpod
import (
"crypto/rand"
"fmt"
+ "net"
"os"
"os/exec"
"path/filepath"
@@ -25,8 +26,8 @@ import (
)
// Get an OCICNI network config
-func getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping) ocicni.PodNetwork {
- return ocicni.PodNetwork{
+func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping, staticIP net.IP) ocicni.PodNetwork {
+ network := ocicni.PodNetwork{
Name: name,
Namespace: name, // TODO is there something else we should put here? We don't know about Kube namespaces
ID: id,
@@ -34,11 +35,21 @@ func getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.Po
PortMappings: ports,
Networks: networks,
}
+
+ if staticIP != nil {
+ defaultNetwork := r.netPlugin.GetDefaultNetworkName()
+
+ network.Networks = []string{defaultNetwork}
+ network.NetworkConfig = make(map[string]ocicni.NetworkConfig)
+ network.NetworkConfig[defaultNetwork] = ocicni.NetworkConfig{IP: staticIP.String()}
+ }
+
+ return network
}
// Create and configure a new network namespace for a container
func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (err error) {
- podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings)
+ podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctrNS.Path(), ctr.config.Networks, ctr.config.PortMappings, ctr.config.StaticIP)
results, err := r.netPlugin.SetUpPod(podNetwork)
if err != nil {
@@ -216,7 +227,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
- podNetwork := getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings)
+ podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, ctr.config.StaticIP)
// The network may have already been torn down, so don't fail here, just log
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
diff --git a/libpod/options.go b/libpod/options.go
index 977f3f4c2..9f966cead 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -828,6 +828,31 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netwo
}
}
+// WithStaticIP indicates that the container should request a static IP from
+// the CNI plugins.
+// It cannot be set unless WithNetNS has already been passed.
+// Further, it cannot be set if additional CNI networks to join have been
+// specified.
+func WithStaticIP(ip net.IP) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return ErrCtrFinalized
+ }
+
+ if !ctr.config.CreateNetNS {
+ return errors.Wrapf(ErrInvalidArg, "cannot set a static IP if the container is not creating a network namespace")
+ }
+
+ if len(ctr.config.Networks) != 0 {
+ return errors.Wrapf(ErrInvalidArg, "cannot set a static IP if joining additional CNI networks")
+ }
+
+ ctr.config.StaticIP = ip
+
+ return nil
+ }
+}
+
// WithLogPath sets the path to the log file.
func WithLogPath(path string) CtrCreateOption {
return func(ctr *Container) error {
diff --git a/libpod/pod_easyjson.go b/libpod/pod_easyjson.go
index 2891e51f2..6c1c939f3 100644
--- a/libpod/pod_easyjson.go
+++ b/libpod/pod_easyjson.go
@@ -1,3 +1,5 @@
+// +build seccomp ostree selinux varlink exclude_graphdriver_devicemapper
+
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
package libpod
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index d78d95453..9eb16c1a5 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -11,6 +11,22 @@
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
+#include <string.h>
+
+static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces";
+static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone";
+
+static int
+syscall_setresuid (uid_t ruid, uid_t euid, uid_t suid)
+{
+ return (int) syscall (__NR_setresuid, ruid, euid, suid);
+}
+
+static int
+syscall_setresgid (gid_t rgid, gid_t egid, gid_t sgid)
+{
+ return (int) syscall (__NR_setresgid, rgid, egid, sgid);
+}
static int
syscall_clone (unsigned long flags, void *child_stack)
@@ -94,9 +110,14 @@ reexec_userns_join (int userns)
argv = get_cmd_line_args (ppid);
if (argv == NULL)
- _exit (EXIT_FAILURE);
+ {
+ fprintf (stderr, "cannot read argv: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
pid = fork ();
+ if (pid < 0)
+ fprintf (stderr, "cannot fork: %s\n", strerror (errno));
if (pid)
return pid;
@@ -104,18 +125,48 @@ reexec_userns_join (int userns)
setenv ("_LIBPOD_ROOTLESS_UID", uid, 1);
if (setns (userns, 0) < 0)
- _exit (EXIT_FAILURE);
+ {
+ fprintf (stderr, "cannot setns: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
close (userns);
- if (setresgid (0, 0, 0) < 0 ||
- setresuid (0, 0, 0) < 0)
- _exit (EXIT_FAILURE);
+ if (syscall_setresgid (0, 0, 0) < 0)
+ {
+ fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (syscall_setresuid (0, 0, 0) < 0)
+ {
+ fprintf (stderr, "cannot setresuid: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
execvp (argv[0], argv);
_exit (EXIT_FAILURE);
}
+static void
+check_proc_sys_userns_file (const char *path)
+{
+ FILE *fp;
+ fp = fopen (path, "r");
+ if (fp)
+ {
+ char buf[32];
+ size_t n_read = fread (buf, 1, sizeof(buf) - 1, fp);
+ if (n_read > 0)
+ {
+ buf[n_read] = '\0';
+ if (strtol (buf, NULL, 10) == 0)
+ fprintf (stderr, "user namespaces are not enabled in %s\n", path);
+ }
+ fclose (fp);
+ }
+}
+
int
reexec_in_user_namespace (int ready)
{
@@ -129,12 +180,22 @@ reexec_in_user_namespace (int ready)
sprintf (uid, "%d", geteuid ());
pid = syscall_clone (CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL);
+ if (pid < 0)
+ {
+ FILE *fp;
+ fprintf (stderr, "cannot clone: %s\n", strerror (errno));
+ check_proc_sys_userns_file (_max_user_namespaces);
+ check_proc_sys_userns_file (_unprivileged_user_namespaces);
+ }
if (pid)
return pid;
argv = get_cmd_line_args (ppid);
if (argv == NULL)
- _exit (EXIT_FAILURE);
+ {
+ fprintf (stderr, "cannot read argv: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
setenv ("_LIBPOD_USERNS_CONFIGURED", "init", 1);
setenv ("_LIBPOD_ROOTLESS_UID", uid, 1);
@@ -143,12 +204,23 @@ reexec_in_user_namespace (int ready)
ret = read (ready, &b, 1) < 0;
while (ret < 0 && errno == EINTR);
if (ret < 0)
- _exit (EXIT_FAILURE);
+ {
+ fprintf (stderr, "cannot read from sync pipe: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
close (ready);
- if (setresgid (0, 0, 0) < 0 ||
- setresuid (0, 0, 0) < 0)
- _exit (EXIT_FAILURE);
+ if (syscall_setresgid (0, 0, 0) < 0)
+ {
+ fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ if (syscall_setresuid (0, 0, 0) < 0)
+ {
+ fprintf (stderr, "cannot setresuid: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
execvp (argv[0], argv);
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 9e8f6253b..d34b21189 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -2,6 +2,7 @@ package createconfig
import (
"encoding/json"
+ "net"
"os"
"strconv"
"strings"
@@ -315,9 +316,6 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
var pod *libpod.Pod
var err error
- // Uncomment after talking to mheon about unimplemented funcs
- // options = append(options, libpod.WithLabels(c.labels))
-
if c.Interactive {
options = append(options, libpod.WithStdin())
}
@@ -446,6 +444,15 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
if logPath != "" {
options = append(options, libpod.WithLogPath(logPath))
}
+ if c.IPAddress != "" {
+ ip := net.ParseIP(c.IPAddress)
+ if ip == nil {
+ return nil, errors.Wrapf(libpod.ErrInvalidArg, "cannot parse %s as IP address", c.IPAddress)
+ } else if ip.To4() == nil {
+ return nil, errors.Wrapf(libpod.ErrInvalidArg, "%s is not an IPv4 address", c.IPAddress)
+ }
+ options = append(options, libpod.WithStaticIP(ip))
+ }
options = append(options, libpod.WithPrivileged(c.Privileged))
diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go
new file mode 100644
index 000000000..b69d15cee
--- /dev/null
+++ b/test/e2e/run_staticip_test.go
@@ -0,0 +1,58 @@
+package integration
+
+import (
+ "fmt"
+ "os"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman run with --ip flag", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest PodmanTest
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanCreate(tempdir)
+ podmanTest.RestoreAllArtifacts()
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
+ GinkgoWriter.Write([]byte(timedResult))
+ })
+
+ It("Podman run --ip with garbage address", func() {
+ result := podmanTest.Podman([]string{"run", "-ti", "--ip", "114232346", ALPINE, "ls"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).ToNot(Equal(0))
+ })
+
+ It("Podman run --ip with v6 address", func() {
+ result := podmanTest.Podman([]string{"run", "-ti", "--ip", "2001:db8:bad:beef::1", ALPINE, "ls"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).ToNot(Equal(0))
+ })
+
+ It("Podman run --ip with non-allocatable IP", func() {
+ result := podmanTest.Podman([]string{"run", "-ti", "--ip", "203.0.113.124", ALPINE, "ls"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).ToNot(Equal(0))
+ })
+
+ It("Podman run with specified static IP has correct IP", func() {
+ result := podmanTest.Podman([]string{"run", "-ti", "--ip", "10.88.64.128", ALPINE, "ip", "addr"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(ContainSubstring("10.88.64.128/16"))
+ })
+})
diff --git a/vendor.conf b/vendor.conf
index d65014992..be89c418e 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -14,7 +14,7 @@ github.com/containers/image 918dbb93e6e099b196b498c38d079f6bb924d0c8
github.com/containers/storage 41294c85d97bef688e18f710402895dbecde3308
github.com/containers/psgo 5dde6da0bc8831b35243a847625bcf18183bd1ee
github.com/coreos/go-systemd v14
-github.com/cri-o/ocicni master
+github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
github.com/cyphar/filepath-securejoin v0.2.1
github.com/davecgh/go-spew v1.1.0
github.com/docker/distribution 7a8efe719e55bbfaff7bc5718cdf0ed51ca821df
@@ -75,6 +75,7 @@ golang.org/x/net c427ad74c6d7a814201695e9ffde0c5d400a7674
golang.org/x/sys master
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631
+golang.org/x/sync master
google.golang.org/grpc v1.0.4 https://github.com/grpc/grpc-go
gopkg.in/cheggaaa/pb.v1 v1.0.7
gopkg.in/inf.v0 v0.9.0
diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
index 33a3ae063..dfc216389 100644
--- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
+++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
@@ -3,6 +3,7 @@ package ocicni
import (
"errors"
"fmt"
+ "net"
"os"
"path"
"sort"
@@ -351,14 +352,14 @@ func (plugin *cniNetworkPlugin) getNetwork(name string) (*cniNetwork, error) {
return net, nil
}
-func (plugin *cniNetworkPlugin) getDefaultNetworkName() string {
+func (plugin *cniNetworkPlugin) GetDefaultNetworkName() string {
plugin.RLock()
defer plugin.RUnlock()
return plugin.defaultNetName
}
func (plugin *cniNetworkPlugin) getDefaultNetwork() *cniNetwork {
- defaultNetName := plugin.getDefaultNetworkName()
+ defaultNetName := plugin.GetDefaultNetworkName()
if defaultNetName == "" {
return nil
}
@@ -383,7 +384,7 @@ func (plugin *cniNetworkPlugin) Name() string {
func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, forEachFunc func(*cniNetwork, string, *PodNetwork) error) error {
networks := podNetwork.Networks
if len(networks) == 0 {
- networks = append(networks, plugin.getDefaultNetworkName())
+ networks = append(networks, plugin.GetDefaultNetworkName())
}
for i, netName := range networks {
// Interface names start at "eth0" and count up for each network
@@ -408,7 +409,7 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Resu
plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork)
- _, err := plugin.loNetwork.addToNetwork(plugin.cacheDir, &podNetwork, "lo")
+ _, err := plugin.loNetwork.addToNetwork(plugin.cacheDir, &podNetwork, "lo", "")
if err != nil {
logrus.Errorf("Error while adding to cni lo network: %s", err)
return nil, err
@@ -416,7 +417,12 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Resu
results := make([]cnitypes.Result, 0)
if err := plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork) error {
- result, err := network.addToNetwork(plugin.cacheDir, podNetwork, ifName)
+ ip := ""
+ if conf, ok := podNetwork.NetworkConfig[network.name]; ok {
+ ip = conf.IP
+ }
+
+ result, err := network.addToNetwork(plugin.cacheDir, podNetwork, ifName, ip)
if err != nil {
logrus.Errorf("Error while adding pod to CNI network %q: %s", network.name, err)
return err
@@ -439,7 +445,12 @@ func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
defer plugin.podUnlock(podNetwork)
return plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork) error {
- if err := network.deleteFromNetwork(plugin.cacheDir, podNetwork, ifName); err != nil {
+ ip := ""
+ if conf, ok := podNetwork.NetworkConfig[network.name]; ok {
+ ip = conf.IP
+ }
+
+ if err := network.deleteFromNetwork(plugin.cacheDir, podNetwork, ifName, ip); err != nil {
logrus.Errorf("Error while removing pod from CNI network %q: %s", network.name, err)
return err
}
@@ -491,8 +502,8 @@ func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]cn
return results, nil
}
-func (network *cniNetwork) addToNetwork(cacheDir string, podNetwork *PodNetwork, ifName string) (cnitypes.Result, error) {
- rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName)
+func (network *cniNetwork) addToNetwork(cacheDir string, podNetwork *PodNetwork, ifName, ip string) (cnitypes.Result, error) {
+ rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, ip)
if err != nil {
logrus.Errorf("Error adding network: %v", err)
return nil, err
@@ -509,8 +520,8 @@ func (network *cniNetwork) addToNetwork(cacheDir string, podNetwork *PodNetwork,
return res, nil
}
-func (network *cniNetwork) deleteFromNetwork(cacheDir string, podNetwork *PodNetwork, ifName string) error {
- rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName)
+func (network *cniNetwork) deleteFromNetwork(cacheDir string, podNetwork *PodNetwork, ifName, ip string) error {
+ rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, ip)
if err != nil {
logrus.Errorf("Error deleting network: %v", err)
return err
@@ -526,7 +537,7 @@ func (network *cniNetwork) deleteFromNetwork(cacheDir string, podNetwork *PodNet
return nil
}
-func buildCNIRuntimeConf(cacheDir string, podNetwork *PodNetwork, ifName string) (*libcni.RuntimeConf, error) {
+func buildCNIRuntimeConf(cacheDir string, podNetwork *PodNetwork, ifName, ip string) (*libcni.RuntimeConf, error) {
logrus.Infof("Got pod network %+v", podNetwork)
rt := &libcni.RuntimeConf{
@@ -542,6 +553,14 @@ func buildCNIRuntimeConf(cacheDir string, podNetwork *PodNetwork, ifName string)
},
}
+ // Add requested static IP to CNI_ARGS
+ if ip != "" {
+ if tstIP := net.ParseIP(ip); tstIP == nil {
+ return nil, fmt.Errorf("unable to parse IP address %q", ip)
+ }
+ rt.Args = append(rt.Args, [2]string{"IP", ip})
+ }
+
if len(podNetwork.PortMappings) == 0 {
return rt, nil
}
diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
index 8ca61657a..d76094292 100644
--- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
+++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
@@ -24,6 +24,14 @@ type PortMapping struct {
HostIP string `json:"hostIP"`
}
+// NetworkConfig is additional configuration for a single CNI network.
+type NetworkConfig struct {
+ // IP is a static IP to be specified in the network. Can only be used
+ // with the hostlocal IP allocator. If left unset, an IP will be
+ // dynamically allocated.
+ IP string
+}
+
// PodNetwork configures the network of a pod sandbox.
type PodNetwork struct {
// Name is the name of the sandbox.
@@ -40,6 +48,11 @@ type PodNetwork struct {
// Networks is a list of CNI network names to attach to the sandbox
// Leave this list empty to attach the default network to the sandbox
Networks []string
+
+ // NetworkConfig is configuration specific to a single CNI network.
+ // It is optional, and can be omitted for some or all specified networks
+ // without issue.
+ NetworkConfig map[string]NetworkConfig
}
// CNIPlugin is the interface that needs to be implemented by a plugin
@@ -48,6 +61,10 @@ type CNIPlugin interface {
// for a plugin by name, e.g.
Name() string
+ // GetDefaultNetworkName returns the name of the plugin's default
+ // network.
+ GetDefaultNetworkName() string
+
// SetUpPod is the method called after the sandbox container of
// the pod has been created but before the other containers of the
// pod are launched.