summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjortkoopmans <jort@jabo-solutions.eu>2020-11-25 18:26:22 +0100
committerjortkoopmans <jort@jabo-solutions.eu>2020-11-25 18:27:31 +0100
commit5cfbe0b78e3672dd67cd028b85d816fc19d6a614 (patch)
tree375fe5a96bca7d04154daf63ac9b644ebb1adc34
parenta18365c908d45a8ee9348c5e32a240a7b9a4091b (diff)
downloadpodman-5cfbe0b78e3672dd67cd028b85d816fc19d6a614.tar.gz
podman-5cfbe0b78e3672dd67cd028b85d816fc19d6a614.tar.bz2
podman-5cfbe0b78e3672dd67cd028b85d816fc19d6a614.zip
squash
Signed-off-by: jortkoopmans <jort@jabo-solutions.eu>
-rw-r--r--changelog.txt30
-rw-r--r--cmd/podman/common/completion.go251
-rw-r--r--cmd/podman/common/create.go18
-rw-r--r--cmd/podman/common/create_opts.go153
-rw-r--r--cmd/podman/common/createparse.go2
-rw-r--r--cmd/podman/common/netflags.go34
-rw-r--r--cmd/podman/common/volumes.go102
-rw-r--r--cmd/podman/containers/ps.go20
-rw-r--r--cmd/podman/containers/top.go10
-rw-r--r--cmd/podman/images/list.go3
-rw-r--r--cmd/podman/images/load.go2
-rw-r--r--cmd/podman/networks/connect.go2
-rw-r--r--cmd/podman/networks/disconnect.go2
-rw-r--r--cmd/podman/networks/list.go2
-rw-r--r--cmd/podman/networks/rm.go1
-rw-r--r--cmd/podman/pods/create.go30
-rw-r--r--cmd/podman/pods/top.go2
-rw-r--r--cmd/podman/root.go52
-rw-r--r--cmd/podman/volumes/list.go2
-rw-r--r--contrib/systemd/system/podman.service3
-rw-r--r--docs/source/Tutorials.rst2
-rw-r--r--docs/source/conf.py4
-rw-r--r--docs/source/managecontainers.rst2
-rw-r--r--docs/source/markdown/links/podman-list.11
-rw-r--r--docs/source/markdown/links/podman-ls.11
-rw-r--r--docs/source/markdown/podman-container.1.md1
-rw-r--r--docs/source/markdown/podman-create.1.md9
-rw-r--r--docs/source/markdown/podman-export.1.md2
-rw-r--r--docs/source/markdown/podman-import.1.md1
-rw-r--r--docs/source/markdown/podman-load.1.md3
-rw-r--r--docs/source/markdown/podman-ps.1.md8
-rw-r--r--docs/source/markdown/podman-run.1.md9
-rw-r--r--docs/source/markdown/podman-save.1.md4
-rw-r--r--docs/source/markdown/podman-system-service.1.md5
-rw-r--r--docs/source/markdown/podman-top.1.md2
-rw-r--r--docs/source/markdown/podman.1.md12
-rw-r--r--docs/tutorials/mac_win_client.md2
-rw-r--r--go.mod6
-rw-r--r--go.sum12
-rw-r--r--libpod/container.go55
-rw-r--r--libpod/container_api.go14
-rw-r--r--libpod/container_internal.go37
-rw-r--r--libpod/healthcheck_linux.go4
-rw-r--r--libpod/image/manifests.go36
-rw-r--r--libpod/network/config.go10
-rw-r--r--libpod/network/create.go1
-rw-r--r--libpod/network/netconflist.go7
-rw-r--r--libpod/network/subnet.go14
-rw-r--r--libpod/network/subnet_test.go62
-rw-r--r--libpod/networking_linux.go28
-rw-r--r--libpod/rootless_cni_linux.go4
-rw-r--r--pkg/api/handlers/compat/containers.go15
-rw-r--r--pkg/api/handlers/compat/containers_create.go21
-rw-r--r--pkg/api/handlers/compat/info.go3
-rw-r--r--pkg/api/handlers/libpod/containers.go24
-rw-r--r--pkg/api/handlers/types.go13
-rw-r--r--pkg/api/server/handler_api.go7
-rw-r--r--pkg/api/server/listener_api.go1
-rw-r--r--pkg/api/server/server.go6
-rw-r--r--pkg/bindings/containers/containers.go12
-rw-r--r--pkg/domain/entities/images.go8
-rw-r--r--pkg/domain/infra/abi/containers.go15
-rw-r--r--pkg/domain/infra/tunnel/containers.go25
-rw-r--r--pkg/specgen/generate/container_create.go12
-rw-r--r--pkg/specgen/generate/storage.go61
-rw-r--r--pkg/specgen/namespaces.go6
-rw-r--r--pkg/specgen/specgen.go38
-rw-r--r--pkg/specgen/volumes.go149
-rw-r--r--test/apiv2/rest_api/__init__.py15
-rw-r--r--test/apiv2/rest_api/test_rest_v2_0_0.py90
-rw-r--r--test/apiv2/rest_api/v1_test_rest_v1_0_0.py4
-rw-r--r--test/e2e/config/containers-remote.conf51
-rw-r--r--test/e2e/containers_conf_test.go68
-rw-r--r--test/e2e/create_staticmac_test.go18
-rw-r--r--test/e2e/network_test.go55
-rw-r--r--test/e2e/pod_create_test.go20
-rw-r--r--test/e2e/ps_test.go6
-rw-r--r--test/e2e/run_networking_test.go29
-rw-r--r--test/e2e/run_test.go4
-rw-r--r--test/python/docker/__init__.py14
-rw-r--r--test/python/docker/common.py4
-rw-r--r--test/python/docker/test_containers.py2
-rw-r--r--test/python/docker/test_images.py4
-rw-r--r--vendor/github.com/containers/common/pkg/config/config.go4
-rw-r--r--vendor/github.com/containers/common/pkg/config/containers.conf10
-rw-r--r--vendor/github.com/containers/common/pkg/config/default.go4
-rw-r--r--vendor/github.com/containers/common/pkg/retry/retry.go2
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/default_linux.go2
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/supported.go2
-rw-r--r--vendor/github.com/containers/common/version/version.go2
-rw-r--r--vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go2
-rw-r--r--vendor/github.com/containers/image/v5/version/version.go2
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/go.mod2
-rw-r--r--vendor/github.com/containers/storage/go.sum4
-rw-r--r--vendor/github.com/containers/storage/pkg/unshare/unshare.go1
-rw-r--r--vendor/github.com/klauspost/compress/flate/gen_inflate.go114
-rw-r--r--vendor/github.com/klauspost/compress/flate/inflate.go7
-rw-r--r--vendor/github.com/klauspost/compress/flate/inflate_gen.go456
-rw-r--r--vendor/github.com/klauspost/compress/zstd/README.md4
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decoder.go10
-rw-r--r--vendor/modules.txt8
102 files changed, 1687 insertions, 830 deletions
diff --git a/changelog.txt b/changelog.txt
index 4d423ca44..326f52718 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,33 @@
+- Changelog for HEAD (2020-11-24):
+ * Set PATH env in systemd timer.
+ * Docker compat API fixes
+ * shell completions: remove usage of ShellCompDirectiveError
+ * more shell completion improvements
+ * Fix ip-range for classless subnet masks
+ * Bump github.com/containers/common from 0.27.0 to 0.29.0
+ * Add podman container ps command
+ * clarify ps(1) fallback of `podman top`
+ * APIv2 - create container sets wrong entrypoint
+ * Enable remote shell completion without a running endpoint
+ * Specify what the replace flag replaces in help text
+ * APIv2 - strip CAP_ prefix from capabilities in json
+ * Make c.networks() list include the default network
+ * Allow containers to --restart on-failure with --rm
+ * REST API v2 - list of images - mandatory Created attribute
+ * Allow multiple --network flags for podman run/create
+ * fix container cgroup lookup
+ * Make podman service log events
+ * vendor in containers/storage v1.24.1 containers/image v5.8.1
+ * Document containers.conf settings for remote connections
+ * Shell completion for podman ps and podman pod ps --filter
+ * Add alias for podman network rm -> remove
+ * add network connect|disconnect compat endpoints
+ * Fix sed regex to update version in version/version.go
+ * Github-Actions: Send e-mail on Cirrus cron failure
+ * Align the podman pod ps --filter behavior with podman ps
+ * podman-remote network rm --force is broken
+ * Remove build \!remote flags from test
+
- Changelog for v2.2.0-rc1 (2020-11-18):
* Add release notes for v2.2.0-RC1
* correct numbering typo
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index db4d3d0d3..9856e46ef 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -12,7 +12,9 @@ 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/containers/podman/v2/pkg/util"
"github.com/spf13/cobra"
)
@@ -36,7 +38,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,10 +77,15 @@ 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
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for _, c := range containers {
@@ -68,7 +103,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,10 +112,15 @@ 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.ShellCompDirectiveError
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ pods, err := engine.PodPs(registry.GetContext(), listOpts)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for _, pod := range pods {
@@ -98,14 +138,19 @@ 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
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for _, v := range volumes {
@@ -116,14 +161,19 @@ 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
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for _, image := range images {
@@ -166,19 +216,24 @@ func getRegistries() ([]string, cobra.ShellCompDirective) {
regs, err := registries.GetRegistries()
if err != nil {
cobra.CompErrorln(err.Error())
- return nil, cobra.ShellCompDirectiveError
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
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
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for _, n := range networks {
@@ -266,7 +321,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 +329,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 +337,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 +345,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 +353,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 +361,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 +369,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 +378,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 +386,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 +396,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 +406,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 +414,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 +423,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 +442,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 +451,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) {
@@ -410,6 +465,37 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
return nil, cobra.ShellCompDirectiveNoFileComp
}
+// AutocompleteNetworkConnectCmd - Autocomplete podman network connect/disconnect command args.
+func AutocompleteNetworkConnectCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if len(args) == 0 {
+ return getNetworks(cmd, toComplete)
+ }
+ if len(args) == 1 {
+ return getContainers(cmd, toComplete, completeDefault)
+ }
+ // don't complete more than 2 args
+ return nil, cobra.ShellCompDirectiveNoFileComp
+}
+
+// AutocompleteTopCmd - Autocomplete podman top/pod top command args.
+func AutocompleteTopCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ latest := cmd.Flags().Lookup("latest")
+ // only complete containers/pods as first arg if latest is not set
+ if len(args) == 0 && (latest == nil || !latest.Changed) {
+ if cmd.Parent().Name() == "pod" {
+ // need to complete pods since we are using pod top
+ return getPods(cmd, toComplete, completeDefault)
+ }
+ return getContainers(cmd, toComplete, completeDefault)
+ }
+ descriptors, err := util.GetContainerPidInformationDescriptors()
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ return descriptors, cobra.ShellCompDirectiveNoFileComp
+}
+
// AutocompleteSystemConnections - Autocomplete system connections.
func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if !validCurrentCmdLine(cmd, args, toComplete) {
@@ -419,7 +505,7 @@ func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete
cfg, err := config.ReadCustomConfig()
if err != nil {
cobra.CompErrorln(err.Error())
- return nil, cobra.ShellCompDirectiveError
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for k, v := range cfg.Engine.ServiceDestinations {
@@ -464,7 +550,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,
@@ -567,7 +653,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
// but at this point we don't know the image.
file, err := os.Open("/etc/group")
if err != nil {
- return nil, cobra.ShellCompDirectiveError
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
defer file.Close()
@@ -583,7 +670,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
}
}
if err = scanner.Err(); err != nil {
- return nil, cobra.ShellCompDirectiveError
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
return groups, cobra.ShellCompDirectiveNoFileComp
}
@@ -592,7 +680,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
// but at this point we don't know the image.
file, err := os.Open("/etc/passwd")
if err != nil {
- return nil, cobra.ShellCompDirectiveError
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
defer file.Close()
@@ -607,7 +696,7 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string)
}
}
if err = scanner.Err(); err != nil {
- return nil, cobra.ShellCompDirectiveError
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
return users, cobra.ShellCompDirectiveNoSpace
}
@@ -623,7 +712,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
@@ -641,8 +730,22 @@ func AutocompleteJSONFormat(cmd *cobra.Command, args []string, toComplete string
// AutocompleteEventFilter - Autocomplete event filter flag options.
// -> "container=", "event=", "image=", "pod=", "volume=", "type="
func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- filters := []string{"container=", "event=", "image=", "pod=", "volume=", "type="}
- return filters, cobra.ShellCompDirectiveNoSpace
+ eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"attach", "checkpoint", "cleanup", "commit", "create", "exec",
+ "export", "import", "init", "kill", "mount", "pause", "prune", "remove",
+ "restart", "restore", "start", "stop", "sync", "unmount", "unpause",
+ "pull", "push", "save", "tag", "untag", "refresh", "renumber",
+ }, cobra.ShellCompDirectiveNoFileComp
+ }
+ kv := keyValueCompletion{
+ "container=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) },
+ "image=": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) },
+ "pod=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeDefault) },
+ "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
+ "event=": eventTypes,
+ "type=": eventTypes,
+ }
+ return completeKeyValues(toComplete, kv)
}
// AutocompleteSystemdRestartOptions - Autocomplete systemd restart options.
@@ -753,15 +856,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 +879,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
@@ -792,3 +895,47 @@ func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete stri
}
return completeKeyValues(toComplete, kv)
}
+
+// AutocompleteImageFilters - Autocomplete image ls --filter options.
+func AutocompleteImageFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ getBool := func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
+ }
+ getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }
+ kv := keyValueCompletion{
+ "before=": getImg,
+ "since=": getImg,
+ "label=": nil,
+ "reference=": nil,
+ "dangling=": getBool,
+ "readonly=": getBool,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteNetworkFilters - Autocomplete network ls --filter options.
+func AutocompleteNetworkFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ kv := keyValueCompletion{
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s) },
+ "plugin=": nil,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// AutocompleteVolumeFilters - Autocomplete volume ls --filter options.
+func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ local := func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
+ }
+ kv := keyValueCompletion{
+ "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
+ "driver=": local,
+ "scope=": local,
+ "label=": nil,
+ "opt=": nil,
+ "dangling=": func(_ string) ([]string, cobra.ShellCompDirective) {
+ return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp
+ },
+ }
+ return completeKeyValues(toComplete, kv)
+}
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index ab3a984f0..599b430ea 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -84,7 +84,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
cgroupsFlagName := "cgroups"
createFlags.StringVar(
&cf.CGroupsMode,
- cgroupsFlagName, containerConfig.Cgroups(),
+ cgroupsFlagName, cgroupConfig(),
`control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`,
)
_ = cmd.RegisterFlagCompletionFunc(cgroupsFlagName, AutocompleteCgroupMode)
@@ -180,7 +180,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
deviceFlagName := "device"
createFlags.StringSliceVar(
&cf.Devices,
- deviceFlagName, containerConfig.Devices(),
+ deviceFlagName, devices(),
fmt.Sprintf("Add a host device to the container"),
)
_ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault)
@@ -238,7 +238,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
envFlagName := "env"
createFlags.StringArrayP(
- envFlagName, "e", containerConfig.Env(),
+ envFlagName, "e", env(),
"Set environment variables in container",
)
_ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone)
@@ -357,7 +357,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
initPathFlagName := "init-path"
createFlags.StringVar(
&cf.InitPath,
- initPathFlagName, containerConfig.InitPath(),
+ initPathFlagName, initPath(),
// Do not use the Value field for setting the default value to determine user input (i.e., non-empty string)
fmt.Sprintf("Path to the container-init binary"),
)
@@ -508,7 +508,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
pidsLimitFlagName := "pids-limit"
createFlags.Int64(
- pidsLimitFlagName, containerConfig.PidsLimit(),
+ pidsLimitFlagName, pidsLimit(),
"Tune container pids limit (set 0 for unlimited, -1 for server defaults)",
)
_ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone)
@@ -543,7 +543,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
pullFlagName := "pull"
createFlags.StringVar(
&cf.Pull,
- pullFlagName, containerConfig.Engine.PullPolicy,
+ pullFlagName, policy(),
`Pull image before creating ("always"|"missing"|"never")`,
)
_ = cmd.RegisterFlagCompletionFunc(pullFlagName, AutocompletePullOption)
@@ -606,7 +606,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
shmSizeFlagName := "shm-size"
createFlags.String(
- shmSizeFlagName, containerConfig.ShmSize(),
+ shmSizeFlagName, shmSize(),
"Size of /dev/shm "+sizeWithUnitFormat,
)
_ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone)
@@ -715,7 +715,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
ulimitFlagName := "ulimit"
createFlags.StringSliceVar(
&cf.Ulimit,
- ulimitFlagName, containerConfig.Ulimits(),
+ ulimitFlagName, ulimits(),
"Ulimit options",
)
_ = cmd.RegisterFlagCompletionFunc(ulimitFlagName, completion.AutocompleteNone)
@@ -753,7 +753,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
volumeFlagName := "volume"
createFlags.StringArrayVarP(
&cf.Volume,
- volumeFlagName, "v", containerConfig.Volumes(),
+ volumeFlagName, "v", volumes(),
"Bind mount a volume into the container",
)
_ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag)
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 4b52663c3..6dc43dbc6 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -6,6 +6,7 @@ import (
"strconv"
"strings"
+ "github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/pkg/api/handlers"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -133,10 +134,9 @@ func stringMaptoArray(m map[string]string) []string {
// a specgen spec.
func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) {
var (
- aliases []string
capAdd []string
cappDrop []string
- entrypoint string
+ entrypoint *string
init bool
specPorts []specgen.PortMapping
)
@@ -180,13 +180,14 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
// marshall it to json; otherwise it should just be the string
// value
if len(cc.Config.Entrypoint) > 0 {
- entrypoint = cc.Config.Entrypoint[0]
+ entrypoint = &cc.Config.Entrypoint[0]
if len(cc.Config.Entrypoint) > 1 {
b, err := json.Marshal(cc.Config.Entrypoint)
if err != nil {
return nil, nil, err
}
- entrypoint = string(b)
+ var jsonString = string(b)
+ entrypoint = &jsonString
}
}
@@ -210,7 +211,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
mounts = append(mounts, mount)
}
- //volumes
+ // volumes
volumes := make([]string, 0, len(cc.Config.Volumes))
for v := range cc.Config.Volumes {
volumes = append(volumes, v)
@@ -240,16 +241,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
}
}
- // network names
- endpointsConfig := cc.NetworkingConfig.EndpointsConfig
- cniNetworks := make([]string, 0, len(endpointsConfig))
- for netName, endpoint := range endpointsConfig {
- cniNetworks = append(cniNetworks, netName)
- if len(endpoint.Aliases) > 0 {
- aliases = append(aliases, endpoint.Aliases...)
- }
- }
-
// netMode
nsmode, _, err := specgen.ParseNetworkNamespace(cc.HostConfig.NetworkMode.NetworkName())
if err != nil {
@@ -266,8 +257,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
// defined when there is only one network.
netInfo := entities.NetOptions{
AddHosts: cc.HostConfig.ExtraHosts,
- Aliases: aliases,
- CNINetworks: cniNetworks,
DNSOptions: cc.HostConfig.DNSOptions,
DNSSearch: cc.HostConfig.DNSSearch,
DNSServers: dns,
@@ -275,31 +264,58 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
PublishPorts: specPorts,
}
- // static IP and MAC
- if len(endpointsConfig) == 1 {
- for _, ep := range endpointsConfig {
- // if IP address is provided
- if len(ep.IPAddress) > 0 {
- staticIP := net.ParseIP(ep.IPAddress)
- netInfo.StaticIP = &staticIP
+ // network names
+ switch {
+ case len(cc.NetworkingConfig.EndpointsConfig) > 0:
+ var aliases []string
+
+ endpointsConfig := cc.NetworkingConfig.EndpointsConfig
+ cniNetworks := make([]string, 0, len(endpointsConfig))
+ for netName, endpoint := range endpointsConfig {
+
+ cniNetworks = append(cniNetworks, netName)
+
+ if endpoint == nil {
+ continue
}
- // If MAC address is provided
- if len(ep.MacAddress) > 0 {
- staticMac, err := net.ParseMAC(ep.MacAddress)
- if err != nil {
- return nil, nil, err
+ if len(endpoint.Aliases) > 0 {
+ aliases = append(aliases, endpoint.Aliases...)
+ }
+ }
+
+ // static IP and MAC
+ if len(endpointsConfig) == 1 {
+ for _, ep := range endpointsConfig {
+ if ep == nil {
+ continue
+ }
+ // if IP address is provided
+ if len(ep.IPAddress) > 0 {
+ staticIP := net.ParseIP(ep.IPAddress)
+ netInfo.StaticIP = &staticIP
+ }
+ // If MAC address is provided
+ if len(ep.MacAddress) > 0 {
+ staticMac, err := net.ParseMAC(ep.MacAddress)
+ if err != nil {
+ return nil, nil, err
+ }
+ netInfo.StaticMAC = &staticMac
}
- netInfo.StaticMAC = &staticMac
+ break
}
- break
}
+ netInfo.Aliases = aliases
+ netInfo.CNINetworks = cniNetworks
+ case len(cc.HostConfig.NetworkMode) > 0:
+ netInfo.CNINetworks = []string{string(cc.HostConfig.NetworkMode)}
}
// Note: several options here are marked as "don't need". this is based
// on speculation by Matt and I. We think that these come into play later
// like with start. We believe this is just a difference in podman/compat
cliOpts := ContainerCLIOpts{
- //Attach: nil, // dont need?
+ // Attach: nil, // dont need?
Authfile: "",
CapAdd: append(capAdd, cc.HostConfig.CapAdd...),
CapDrop: append(cappDrop, cc.HostConfig.CapDrop...),
@@ -310,18 +326,18 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod),
CPURTRuntime: cc.HostConfig.CPURealtimeRuntime,
CPUShares: uint64(cc.HostConfig.CPUShares),
- //CPUS: 0, // dont need?
+ // CPUS: 0, // dont need?
CPUSetCPUs: cc.HostConfig.CpusetCpus,
CPUSetMems: cc.HostConfig.CpusetMems,
- //Detach: false, // dont need
- //DetachKeys: "", // dont need
+ // Detach: false, // dont need
+ // DetachKeys: "", // dont need
Devices: devices,
DeviceCGroupRule: nil,
DeviceReadBPs: readBps,
DeviceReadIOPs: readIops,
DeviceWriteBPs: writeBps,
DeviceWriteIOPs: writeIops,
- Entrypoint: &entrypoint,
+ Entrypoint: entrypoint,
Env: cc.Config.Env,
Expose: expose,
GroupAdd: cc.HostConfig.GroupAdd,
@@ -436,7 +452,70 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
}
// specgen assumes the image name is arg[0]
- cmd := []string{cc.Image}
+ cmd := []string{cc.Config.Image}
cmd = append(cmd, cc.Config.Cmd...)
return &cliOpts, cmd, nil
}
+
+func ulimits() []string {
+ if !registry.IsRemote() {
+ return containerConfig.Ulimits()
+ }
+ return nil
+}
+
+func cgroupConfig() string {
+ if !registry.IsRemote() {
+ return containerConfig.Cgroups()
+ }
+ return ""
+}
+
+func devices() []string {
+ if !registry.IsRemote() {
+ return containerConfig.Devices()
+ }
+ return nil
+}
+
+func env() []string {
+ if !registry.IsRemote() {
+ return containerConfig.Env()
+ }
+ return nil
+}
+
+func initPath() string {
+ if !registry.IsRemote() {
+ return containerConfig.InitPath()
+ }
+ return ""
+}
+
+func pidsLimit() int64 {
+ if !registry.IsRemote() {
+ return containerConfig.PidsLimit()
+ }
+ return -1
+}
+
+func policy() string {
+ if !registry.IsRemote() {
+ return containerConfig.Engine.PullPolicy
+ }
+ return ""
+}
+
+func shmSize() string {
+ if !registry.IsRemote() {
+ return containerConfig.ShmSize()
+ }
+ return ""
+}
+
+func volumes() []string {
+ if !registry.IsRemote() {
+ return containerConfig.Volumes()
+ }
+ return nil
+}
diff --git a/cmd/podman/common/createparse.go b/cmd/podman/common/createparse.go
index 09ee5aa0c..3a69f11b6 100644
--- a/cmd/podman/common/createparse.go
+++ b/cmd/podman/common/createparse.go
@@ -9,7 +9,7 @@ import (
// by validate must not need any state information on the flag (i.e. changed)
func (c *ContainerCLIOpts) validate() error {
var ()
- if c.Rm && c.Restart != "" && c.Restart != "no" {
+ if c.Rm && (c.Restart != "" && c.Restart != "no" && c.Restart != "on-failure") {
return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`)
}
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/common/volumes.go b/cmd/podman/common/volumes.go
index b3c160ddf..0468f15e0 100644
--- a/cmd/podman/common/volumes.go
+++ b/cmd/podman/common/volumes.go
@@ -10,7 +10,6 @@ import (
"github.com/containers/podman/v2/pkg/util"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
const (
@@ -45,7 +44,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo
}
// Next --volumes flag.
- volumeMounts, volumeVolumes, overlayVolumes, err := getVolumeMounts(volumeFlag)
+ volumeMounts, volumeVolumes, overlayVolumes, err := specgen.GenVolumeMounts(volumeFlag)
if err != nil {
return nil, nil, nil, nil, err
}
@@ -594,105 +593,6 @@ func getImageVolume(args []string) (*specgen.ImageVolume, error) {
return newVolume, nil
}
-func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.OverlayVolume, error) {
- mounts := make(map[string]spec.Mount)
- volumes := make(map[string]*specgen.NamedVolume)
- overlayVolumes := make(map[string]*specgen.OverlayVolume)
-
- volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]")
-
- for _, vol := range volumeFlag {
- var (
- options []string
- src string
- dest string
- err error
- )
-
- splitVol := strings.Split(vol, ":")
- if len(splitVol) > 3 {
- return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol)
- }
-
- src = splitVol[0]
- if len(splitVol) == 1 {
- // This is an anonymous named volume. Only thing given
- // is destination.
- // Name/source will be blank, and populated by libpod.
- src = ""
- dest = splitVol[0]
- } else if len(splitVol) > 1 {
- dest = splitVol[1]
- }
- if len(splitVol) > 2 {
- if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil {
- return nil, nil, nil, err
- }
- }
-
- // Do not check source dir for anonymous volumes
- if len(splitVol) > 1 {
- if err := parse.ValidateVolumeHostDir(src); err != nil {
- return nil, nil, nil, err
- }
- }
- if err := parse.ValidateVolumeCtrDir(dest); err != nil {
- return nil, nil, nil, err
- }
-
- cleanDest := filepath.Clean(dest)
-
- if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") {
- // This is not a named volume
- overlayFlag := false
- for _, o := range options {
- if o == "O" {
- overlayFlag = true
- if len(options) > 1 {
- return nil, nil, nil, errors.New("can't use 'O' with other options")
- }
- }
- }
- if overlayFlag {
- // This is a overlay volume
- newOverlayVol := new(specgen.OverlayVolume)
- newOverlayVol.Destination = cleanDest
- newOverlayVol.Source = src
- if _, ok := overlayVolumes[newOverlayVol.Destination]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination)
- }
- overlayVolumes[newOverlayVol.Destination] = newOverlayVol
- } else {
- newMount := spec.Mount{
- Destination: cleanDest,
- Type: string(TypeBind),
- Source: src,
- Options: options,
- }
- if _, ok := mounts[newMount.Destination]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination)
- }
- mounts[newMount.Destination] = newMount
- }
- } else {
- // This is a named volume
- newNamedVol := new(specgen.NamedVolume)
- newNamedVol.Name = src
- newNamedVol.Dest = cleanDest
- newNamedVol.Options = options
-
- if _, ok := volumes[newNamedVol.Dest]; ok {
- return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest)
- }
- volumes[newNamedVol.Dest] = newNamedVol
- }
-
- logrus.Debugf("User mount %s:%s options %v", src, dest, options)
- }
-
- return mounts, volumes, overlayVolumes, nil
-}
-
// GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts
func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) {
m := make(map[string]spec.Mount)
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index a1a41ae08..6f84cf9b8 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -29,15 +29,25 @@ var (
psDescription = "Prints out information about the containers"
psCommand = &cobra.Command{
Use: "ps [options]",
- Args: validate.NoArgs,
Short: "List containers",
Long: psDescription,
RunE: ps,
+ Args: validate.NoArgs,
ValidArgsFunction: completion.AutocompleteNone,
Example: `podman ps -a
podman ps -a --format "{{.ID}} {{.Image}} {{.Labels}} {{.Mounts}}"
podman ps --size --sort names`,
}
+
+ psContainerCommand = &cobra.Command{
+ Use: psCommand.Use,
+ Short: psCommand.Short,
+ Long: psCommand.Long,
+ RunE: psCommand.RunE,
+ Args: psCommand.Args,
+ ValidArgsFunction: psCommand.ValidArgsFunction,
+ Example: strings.ReplaceAll(psCommand.Example, "podman ps", "podman container ps"),
+ }
)
var (
listOpts = entities.ContainerListOptions{
@@ -54,6 +64,14 @@ func init() {
})
listFlagSet(psCommand)
validate.AddLatestFlag(psCommand, &listOpts.Latest)
+
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: psContainerCommand,
+ Parent: containerCmd,
+ })
+ listFlagSet(psContainerCommand)
+ validate.AddLatestFlag(psContainerCommand, &listOpts.Latest)
}
func listFlagSet(cmd *cobra.Command) {
diff --git a/cmd/podman/containers/top.go b/cmd/podman/containers/top.go
index 3eb6d2af2..e691f527a 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{
@@ -32,7 +30,7 @@ var (
Long: topDescription,
RunE: top,
Args: cobra.ArbitraryArgs,
- ValidArgsFunction: common.AutocompleteContainersRunning,
+ ValidArgsFunction: common.AutocompleteTopCmd,
Example: `podman top ctrID
podman top --latest
podman top ctrID pid seccomp args %C
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index 4692699f2..bcb31e6ee 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -79,8 +79,7 @@ func imageListFlagSet(cmd *cobra.Command) {
filterFlagName := "filter"
flags.StringSliceVarP(&listOptions.Filter, filterFlagName, "f", []string{}, "Filter output based on conditions provided (default [])")
- // TODO: add completion function for filters
- _ = cmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
+ _ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteImageFilters)
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "", "Change the output format to JSON or a Go template")
diff --git a/cmd/podman/images/load.go b/cmd/podman/images/load.go
index a7884f4c5..a24f46781 100644
--- a/cmd/podman/images/load.go
+++ b/cmd/podman/images/load.go
@@ -23,7 +23,7 @@ var (
loadDescription = "Loads an image from a locally stored archive (tar file) into container storage."
loadCommand = &cobra.Command{
Use: "load [options] [NAME[:TAG]]",
- Short: "Load an image from container archive",
+ Short: "Load image(s) from a tar archive",
Long: loadDescription,
RunE: load,
Args: cobra.MaximumNArgs(1),
diff --git a/cmd/podman/networks/connect.go b/cmd/podman/networks/connect.go
index a7636688c..8afc0c7c0 100644
--- a/cmd/podman/networks/connect.go
+++ b/cmd/podman/networks/connect.go
@@ -17,7 +17,7 @@ var (
RunE: networkConnect,
Example: `podman network connect web secondary`,
Args: cobra.ExactArgs(2),
- ValidArgsFunction: common.AutocompleteNetworks,
+ ValidArgsFunction: common.AutocompleteNetworkConnectCmd,
}
)
diff --git a/cmd/podman/networks/disconnect.go b/cmd/podman/networks/disconnect.go
index 598c23a1c..a30315774 100644
--- a/cmd/podman/networks/disconnect.go
+++ b/cmd/podman/networks/disconnect.go
@@ -17,7 +17,7 @@ var (
RunE: networkDisconnect,
Example: `podman network disconnect web secondary`,
Args: cobra.ExactArgs(2),
- ValidArgsFunction: common.AutocompleteNetworks,
+ ValidArgsFunction: common.AutocompleteNetworkConnectCmd,
}
)
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go
index f2a5a431a..dcba3f186 100644
--- a/cmd/podman/networks/list.go
+++ b/cmd/podman/networks/list.go
@@ -46,7 +46,7 @@ func networkListFlags(flags *pflag.FlagSet) {
filterFlagName := "filter"
flags.StringVarP(&networkListOptions.Filter, filterFlagName, "", "", "Provide filter values (e.g. 'name=podman')")
- _ = networklistCommand.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
+ _ = networklistCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteNetworkFilters)
}
diff --git a/cmd/podman/networks/rm.go b/cmd/podman/networks/rm.go
index 34e756a3a..1504d9385 100644
--- a/cmd/podman/networks/rm.go
+++ b/cmd/podman/networks/rm.go
@@ -18,6 +18,7 @@ var (
networkrmDescription = `Remove networks`
networkrmCommand = &cobra.Command{
Use: "rm [options] NETWORK [NETWORK...]",
+ Aliases: []string{"remove"},
Short: "network rm",
Long: networkrmDescription,
RunE: networkRm,
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/pods/top.go b/cmd/podman/pods/top.go
index 45ef1e7c2..829882080 100644
--- a/cmd/podman/pods/top.go
+++ b/cmd/podman/pods/top.go
@@ -29,7 +29,7 @@ var (
Long: topDescription,
RunE: top,
Args: cobra.ArbitraryArgs,
- ValidArgsFunction: common.AutocompletePodsRunning,
+ ValidArgsFunction: common.AutocompleteTopCmd,
Example: `podman pod top podID
podman pod top --latest
podman pod top podID pid seccomp args %C
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/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go
index b0d999765..7e54de38a 100644
--- a/cmd/podman/volumes/list.go
+++ b/cmd/podman/volumes/list.go
@@ -56,7 +56,7 @@ func init() {
filterFlagName := "filter"
flags.StringSliceVarP(&cliOpts.Filter, filterFlagName, "f", []string{}, "Filter volume output")
- _ = lsCommand.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
+ _ = lsCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteVolumeFilters)
formatFlagName := "format"
flags.StringVar(&cliOpts.Format, formatFlagName, "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
diff --git a/contrib/systemd/system/podman.service b/contrib/systemd/system/podman.service
index e14bbe078..9b5a1a87f 100644
--- a/contrib/systemd/system/podman.service
+++ b/contrib/systemd/system/podman.service
@@ -8,4 +8,5 @@ StartLimitIntervalSec=0
[Service]
Type=notify
KillMode=process
-ExecStart=/usr/bin/podman system service
+Environment=LOGGING="--log-level=info"
+ExecStart=/usr/bin/podman $LOGGING system service
diff --git a/docs/source/Tutorials.rst b/docs/source/Tutorials.rst
index 83818e3ae..e3e869d5b 100644
--- a/docs/source/Tutorials.rst
+++ b/docs/source/Tutorials.rst
@@ -2,7 +2,7 @@
Tutorials
=========
-Here are a number of useful tutorials to get you up and running with Podman. If you are familiar with the Docker `Container Engine`_ the command in Podman_ should be quite familiar. If are brand new to containers, take a look at our `Introduction`.
+Here are a number of useful tutorials to get you up and running with Podman. If you are familiar with the Docker `Container Engine`_ the command in Podman_ should be quite familiar. If you are brand new to containers, take a look at our `Introduction`.
* `Basic Setup and Use of Podman <https://github.com/containers/podman/blob/master/docs/tutorials/podman_tutorial.md>`_: Learn how to setup Podman and perform some basic commands with the utility.
* `Basic Setup and Use of Podman in a Rootless environment <https://github.com/containers/podman/blob/master/docs/tutorials/rootless_tutorial.md>`_: The steps required to setup rootless Podman are enumerated.
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 368d7cc29..e3715937d 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -28,11 +28,11 @@ author = "team"
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
- 'sphinx_markdown_tables',
+ "sphinx_markdown_tables",
]
source_parsers = {
- '.md': 'recommonmark.parser.CommonMarkParser',
+ ".md": "recommonmark.parser.CommonMarkParser",
}
diff --git a/docs/source/managecontainers.rst b/docs/source/managecontainers.rst
index 849fd1d25..9926f9996 100644
--- a/docs/source/managecontainers.rst
+++ b/docs/source/managecontainers.rst
@@ -39,6 +39,8 @@ Manage Containers
:doc:`prune <markdown/podman-container-prune.1>` Remove all stopped containers
+:doc:`ps <markdown/podman-ps.1>` List containers
+
:doc:`restart <markdown/podman-restart.1>` Restart one or more containers
:doc:`restore <markdown/podman-container-restore.1>` Restores one or more containers from a checkpoint
diff --git a/docs/source/markdown/links/podman-list.1 b/docs/source/markdown/links/podman-list.1
deleted file mode 100644
index f7f44c704..000000000
--- a/docs/source/markdown/links/podman-list.1
+++ /dev/null
@@ -1 +0,0 @@
-.so man1/podman-ps.1
diff --git a/docs/source/markdown/links/podman-ls.1 b/docs/source/markdown/links/podman-ls.1
deleted file mode 100644
index f7f44c704..000000000
--- a/docs/source/markdown/links/podman-ls.1
+++ /dev/null
@@ -1 +0,0 @@
-.so man1/podman-ps.1
diff --git a/docs/source/markdown/podman-container.1.md b/docs/source/markdown/podman-container.1.md
index 0a6ceea33..9da5db601 100644
--- a/docs/source/markdown/podman-container.1.md
+++ b/docs/source/markdown/podman-container.1.md
@@ -32,6 +32,7 @@ The container command allows you to manage containers
| pause | [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. |
| port | [podman-port(1)](podman-port.1.md) | List port mappings for the container. |
| prune | [podman-container-prune(1)](podman-container-prune.1.md)| Remove all stopped containers from local storage. |
+| ps | [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. |
| restart | [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. |
| restore | [podman-container-restore(1)](podman-container-restore.1.md) | Restores one or more containers from a checkpoint. |
| rm | [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 749af8a66..eb73609d4 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -18,6 +18,10 @@ any point.
The initial status of the container created with **podman create** is 'created'.
+Default settings for flags are defined in `containers.conf`. Most settings for
+remote connections use the server's containers.conf, except when documented in
+man pages.
+
## OPTIONS
#### **--add-host**=*host*
@@ -584,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:
@@ -817,6 +821,7 @@ Signal to stop a container. Default is SIGTERM.
#### **--stop-timeout**=*seconds*
Timeout (in seconds) to stop a container. Default is 10.
+Remote connections use local containers.conf for defaults
#### **--subgidname**=*name*
@@ -893,10 +898,12 @@ standard input.
#### **--tz**=*timezone*
Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones.
+Remote connections use local containers.conf for defaults
#### **--umask**=*umask*
Set the umask inside the container. Defaults to `0022`.
+Remote connections use local containers.conf for defaults
#### **--uidmap**=*container_uid:host_uid:amount*
diff --git a/docs/source/markdown/podman-export.1.md b/docs/source/markdown/podman-export.1.md
index 647c25770..63989a4db 100644
--- a/docs/source/markdown/podman-export.1.md
+++ b/docs/source/markdown/podman-export.1.md
@@ -12,6 +12,8 @@ podman\-export - Export a container's filesystem contents as a tar archive
**podman export** exports the filesystem of a container and saves it as a tarball
on the local machine. **podman export** writes to STDOUT by default and can be
redirected to a file using the `--output` flag.
+The image of the container exported by **podman export** can be imported by **podman import**.
+To export image(s) with parent layers, use **podman save**.
Note: `:` is a restricted character and cannot be part of the file name.
**podman [GLOBAL OPTIONS]**
diff --git a/docs/source/markdown/podman-import.1.md b/docs/source/markdown/podman-import.1.md
index ebedf90b4..427c67da4 100644
--- a/docs/source/markdown/podman-import.1.md
+++ b/docs/source/markdown/podman-import.1.md
@@ -14,6 +14,7 @@ and saves it as a filesystem image. Remote tarballs can be specified using a URL
Various image instructions can be configured with the **--change** flag and
a commit message can be set using the **--message** flag.
**reference**, if present, is a tag to assign to the image.
+**podman import** is used for importing from the archive generated by **podman export**, that includes the container's filesystem. To import the archive of image layers created by **podman save**, use **podman load**.
Note: `:` is a restricted character and cannot be part of the file name.
## OPTIONS
diff --git a/docs/source/markdown/podman-load.1.md b/docs/source/markdown/podman-load.1.md
index cdc99fbf2..177709a43 100644
--- a/docs/source/markdown/podman-load.1.md
+++ b/docs/source/markdown/podman-load.1.md
@@ -1,7 +1,7 @@
% podman-load(1)
## NAME
-podman\-load - Load an image from a container image archive into container storage
+podman\-load - Load image(s) from a tar archive into container storage
## SYNOPSIS
**podman load** [*options*] [*name*[:*tag*]]
@@ -11,6 +11,7 @@ podman\-load - Load an image from a container image archive into container stora
## DESCRIPTION
**podman load** loads an image from either an **oci-archive** or a **docker-archive** stored on the local machine into container storage. **podman load** reads from stdin by default or a file if the **input** option is set.
You can also specify a name for the image if the archive does not contain a named reference, of if you want an additional name for the local image.
+**podman load** is used for loading from the archive generated by **podman save**, that includes the image parent layers. To load the archive of container's filesystem created by **podman export**, use **podman import**.
The local client further supports loading an **oci-dir** or a **docker-dir** as created with **podman save** (1).
diff --git a/docs/source/markdown/podman-ps.1.md b/docs/source/markdown/podman-ps.1.md
index f542daf4c..b94964f6c 100644
--- a/docs/source/markdown/podman-ps.1.md
+++ b/docs/source/markdown/podman-ps.1.md
@@ -6,15 +6,11 @@ podman\-ps - Prints out information about containers
## SYNOPSIS
**podman ps** [*options*]
-**podman container list** [*options*]
-
-**podman container ls** [*options*]
-
**podman container ps** [*options*]
-**podman list** [*options*]
+**podman container list** [*options*]
-**podman ls** [*options*]
+**podman container ls** [*options*]
## DESCRIPTION
**podman ps** lists the running containers on the system. Use the **--all** flag to view
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 5b2cdd6a5..184c12acd 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -33,6 +33,10 @@ is located at _/run/.containerenv_.
When running from a user defined network namespace, the _/etc/netns/NSNAME/resolv.conf_
will be used if it exists, otherwise _/etc/resolv.conf_ will be used.
+Default settings are defined in `containers.conf`. Most settings for remote
+connections use the servers containers.conf, except when documented in man
+pages.
+
## OPTIONS
#### **--add-host**=_host_:_ip_
@@ -610,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:
@@ -857,6 +861,7 @@ Signal to stop a container. Default is **SIGTERM**.
#### **--stop-timeout**=*seconds*
Timeout to stop a container. Default is **10**.
+Remote connections use local containers.conf for defaults
#### **--subgidname**=*name*
@@ -952,10 +957,12 @@ standard input.
#### **--tz**=*timezone*
Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones.
+Remote connections use local containers.conf for defaults
#### **--umask**=*umask*
Set the umask inside the container. Defaults to `0022`.
+Remote connections use local containers.conf for defaults
#### **--uidmap**=*container_uid*:*host_uid*:*amount*
diff --git a/docs/source/markdown/podman-save.1.md b/docs/source/markdown/podman-save.1.md
index bfb52e7f8..fb79cfd2a 100644
--- a/docs/source/markdown/podman-save.1.md
+++ b/docs/source/markdown/podman-save.1.md
@@ -1,7 +1,7 @@
% podman-save(1)
## NAME
-podman\-save - Save an image to a container archive
+podman\-save - Save image(s) to an archive
## SYNOPSIS
**podman save** [*options*] *name*[:*tag*]
@@ -12,6 +12,8 @@ podman\-save - Save an image to a container archive
**podman save** saves an image to either **docker-archive**, **oci-archive**, **oci-dir** (directory with oci manifest type), or **docker-dir** (directory with v2s2 manifest type) on the local machine,
default is **docker-archive**. **podman save** writes to STDOUT by default and can be redirected to a
file using the **output** flag. The **quiet** flag suppresses the output when set.
+**podman save** will save parent layers of the image(s) and the image(s) can be loaded using **podman load**.
+To export the containers, use the **podman export**.
Note: `:` is a restricted character and cannot be part of the file name.
**podman [GLOBAL OPTIONS]**
diff --git a/docs/source/markdown/podman-system-service.1.md b/docs/source/markdown/podman-system-service.1.md
index 39e30ec02..1fdecfa5c 100644
--- a/docs/source/markdown/podman-system-service.1.md
+++ b/docs/source/markdown/podman-system-service.1.md
@@ -17,12 +17,14 @@ The REST API provided by **podman system service** is split into two parts: a co
Documentation for the latter is available at *https://docs.podman.io/en/latest/_static/api.html*.
Both APIs are versioned, but the server will not reject requests with an unsupported version set.
+Note: The default systemd unit files (system and user) change the log-level option to *info* from *error*. This change provides additional information on each API call.
+
## OPTIONS
#### **--time**, **-t**
The time until the session expires in _seconds_. The default is 5
-seconds. A value of `0` means no timeout and the session will not expire.
+seconds. A value of `0` means no timeout, therefore the session will not expire.
#### **--help**, **-h**
@@ -40,3 +42,4 @@ podman(1), podman-system-service(1), podman-system-connection(1)
## HISTORY
January 2020, Originally compiled by Brent Baude<bbaude@redhat.com>
+November 2020, Updated by Jhon Honce <jhonce at redhat.com>
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/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md
index 1954ca2aa..7da01d389 100644
--- a/docs/source/markdown/podman.1.md
+++ b/docs/source/markdown/podman.1.md
@@ -17,6 +17,10 @@ Podman uses Buildah(1) internally to create container images. Both tools share i
(not container) storage, hence each can use or manipulate images (but not containers)
created by the other.
+Default settings for flags are defined in `containers.conf`. Most settings for
+Remote connections use the server's containers.conf, except when documented in
+man pages.
+
**podman [GLOBAL OPTIONS]**
## GLOBAL OPTIONS
@@ -33,6 +37,7 @@ Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d
#### **--connection**, **-c**
Connection to use for remote podman (Default connection is configured in `containers.conf`)
+Remote connections use local containers.conf for default.
#### **--conmon**
Path of the conmon binary (Default path is configured in `containers.conf`)
@@ -71,6 +76,7 @@ Identity value resolution precedence:
- command line value
- environment variable `CONTAINER_SSHKEY`, if `CONTAINER_HOST` is found
- `containers.conf`
+Remote connections use local containers.conf for default.
#### **--log-level**=*level*
@@ -86,6 +92,7 @@ Path to the command binary to use for setting up a network. It is currently onl
#### **--remote**, **-r**
Access Podman service will be remote
+Remote connections use local containers.conf for default.
#### **--url**=*value*
URL to access Podman service (default from `containers.conf`, rootless `unix://run/user/$UID/podman/podman.sock` or as root `unix://run/podman/podman.sock`).
@@ -104,6 +111,7 @@ URL value resolution precedence:
- environment variable `CONTAINER_HOST`
- `containers.conf`
- `unix://run/podman/podman.sock`
+Remote connections use local containers.conf for default.
#### **--root**=*value*
@@ -223,7 +231,7 @@ the exit codes follow the `chroot` standard, see below:
| [podman-init(1)](podman-init.1.md) | Initialize one or more containers |
| [podman-inspect(1)](podman-inspect.1.md) | Display a container, image, volume, network, or pod's configuration. |
| [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. |
-| [podman-load(1)](podman-load.1.md) | Load an image from a container image archive into container storage. |
+| [podman-load(1)](podman-load.1.md) | Load image(s) from a tar archive into container storage. |
| [podman-login(1)](podman-login.1.md) | Login to a container registry. |
| [podman-logout(1)](podman-logout.1.md) | Logout of a container registry. |
| [podman-logs(1)](podman-logs.1.md) | Display the logs of one or more containers. |
@@ -241,7 +249,7 @@ the exit codes follow the `chroot` standard, see below:
| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. |
| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. |
| [podman-run(1)](podman-run.1.md) | Run a command in a new container. |
-| [podman-save(1)](podman-save.1.md) | Save an image to a container archive. |
+| [podman-save(1)](podman-save.1.md) | Save image(s) to an archive. |
| [podman-search(1)](podman-search.1.md) | Search a registry for an image. |
| [podman-start(1)](podman-start.1.md) | Start one or more containers. |
| [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. |
diff --git a/docs/tutorials/mac_win_client.md b/docs/tutorials/mac_win_client.md
index af2668e10..375f73102 100644
--- a/docs/tutorials/mac_win_client.md
+++ b/docs/tutorials/mac_win_client.md
@@ -55,7 +55,7 @@ host:
In order for the client to communicate with the server you need to enable and start the SSH daemon on your Linux machine, if it is not currently enabled.
```
-sudo systemctl enable --now -s sshd
+sudo systemctl enable --now sshd
```
#### Setting up SSH
diff --git a/go.mod b/go.mod
index c093319e8..2ed1c56d1 100644
--- a/go.mod
+++ b/go.mod
@@ -11,11 +11,11 @@ require (
github.com/containernetworking/cni v0.8.0
github.com/containernetworking/plugins v0.8.7
github.com/containers/buildah v1.18.0
- github.com/containers/common v0.27.0
+ github.com/containers/common v0.29.0
github.com/containers/conmon v2.0.20+incompatible
- github.com/containers/image/v5 v5.8.0
+ github.com/containers/image/v5 v5.8.1
github.com/containers/psgo v1.5.1
- github.com/containers/storage v1.24.0
+ github.com/containers/storage v1.24.1
github.com/coreos/go-systemd/v22 v22.1.0
github.com/cri-o/ocicni v0.2.1-0.20201102180012-75c612fda1a2
github.com/cyphar/filepath-securejoin v0.2.2
diff --git a/go.sum b/go.sum
index baff472f6..761ba04de 100644
--- a/go.sum
+++ b/go.sum
@@ -96,13 +96,15 @@ github.com/containernetworking/plugins v0.8.7/go.mod h1:R7lXeZaBzpfqapcAbHRW8/CY
github.com/containers/buildah v1.18.0 h1:mWEm013LVNGecF++sYo0T7fe/4pqMas/PQxQ/qviC68=
github.com/containers/buildah v1.18.0/go.mod h1:qHLk7RUL7cHfA7ve1MKkZ6cyKUxHD0YxiLJcKY+mJe8=
github.com/containers/common v0.26.3/go.mod h1:hJWZIlrl5MsE2ELNRa+MPp6I1kPbXHauuj0Ym4BsLG4=
-github.com/containers/common v0.27.0 h1:+QlYEOitVYtU9/x8xebRgxdGqt4sLaIqV6MBOns+zLk=
-github.com/containers/common v0.27.0/go.mod h1:ZTswJJfu4aGF6Anyi2yON8Getda9NDYcdIzurOEHHXI=
+github.com/containers/common v0.29.0 h1:hTMC+urdkk5bKfhL/OgCixIX5xjJgQ2l2jPG745ECFQ=
+github.com/containers/common v0.29.0/go.mod h1:yT4GTUHsKRmpaDb+mecXRnIMre7W3ZgwXqaYMywXlaA=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/image/v5 v5.7.0/go.mod h1:8aOy+YaItukxghRORkvhq5ibWttHErzDLy6egrKfKos=
github.com/containers/image/v5 v5.8.0 h1:B3FGHi0bdGXgg698kBIGOlHCXN5n+scJr6/5354GOPU=
github.com/containers/image/v5 v5.8.0/go.mod h1:jKxdRtyIDumVa56hdsZvV+gwx4zB50hRou6pIuCWLkg=
+github.com/containers/image/v5 v5.8.1 h1:aHW8a/Kd0dTJ7PTL/fc6y12sJqHxWgqilu+XyHfjD8Q=
+github.com/containers/image/v5 v5.8.1/go.mod h1:blOEFd/iFdeyh891ByhCVUc+xAcaI3gBegXECwz9UbQ=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE=
github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY=
github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c=
@@ -111,10 +113,10 @@ github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA
github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU=
github.com/containers/storage v1.23.6/go.mod h1:haFs0HRowKwyzvWEx9EgI3WsL8XCSnBDb5f8P5CAxJY=
github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI=
-github.com/containers/storage v1.23.9 h1:qbgnTp76pLSyW3vYwY5GH4vk5cHYVXFJ+CsUEBp9TMw=
-github.com/containers/storage v1.23.9/go.mod h1:3b2ktpB6pw53SEeIoFfO0sQfP9+IoJJKPq5iJk74gxE=
github.com/containers/storage v1.24.0 h1:Fo2LkF7tkMLmo38sTZ/G8wHjcn8JfUFPfyTxM4WwMfk=
github.com/containers/storage v1.24.0/go.mod h1:A4d3BzuZK9b3oLVEsiSRhZLPIx3z7utgiPyXLK/YMhY=
+github.com/containers/storage v1.24.1 h1:1+f8fy6ly35c8SLet5jzZ8t0WJJs5+xSpfMAYw0R3kc=
+github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38=
@@ -322,6 +324,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.11.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
+github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
diff --git a/libpod/container.go b/libpod/container.go
index 4b9e6a5ba..e954d84eb 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -13,10 +13,12 @@ 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"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// CgroupfsDefaultCgroupParent is the cgroup parent for CGroupFS in libpod
@@ -920,19 +922,39 @@ func (c *Container) CGroupPath() (string, error) {
return "", errors.Wrapf(define.ErrNoCgroups, "this container is not creating cgroups")
}
- // Read /proc/[PID]/cgroup and look at the first line. cgroups(7)
- // nails it down to three fields with the 3rd pointing to the cgroup's
- // path which works both on v1 and v2.
+ // Read /proc/[PID]/cgroup and find the *longest* cgroup entry. That's
+ // needed to account for hacks in cgroups v1, where each line in the
+ // file could potentially point to a cgroup. The longest one, however,
+ // is the libpod-specific one we're looking for.
+ //
+ // See #8397 on the need for the longest-path look up.
procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID)
lines, err := ioutil.ReadFile(procPath)
if err != nil {
return "", err
}
- fields := bytes.Split(bytes.Split(lines, []byte("\n"))[0], []byte(":"))
- if len(fields) != 3 {
- return "", errors.Errorf("expected 3 fields but got %d: %s", len(fields), procPath)
+
+ var cgroupPath string
+ for _, line := range bytes.Split(lines, []byte("\n")) {
+ // cgroups(7) nails it down to three fields with the 3rd
+ // pointing to the cgroup's path which works both on v1 and v2.
+ fields := bytes.Split(line, []byte(":"))
+ if len(fields) != 3 {
+ logrus.Debugf("Error parsing cgroup: expected 3 fields but got %d: %s", len(fields), procPath)
+ continue
+ }
+ path := string(fields[2])
+ if len(path) > len(cgroupPath) {
+ cgroupPath = path
+ }
+
}
- return string(fields[2]), nil
+
+ if len(cgroupPath) == 0 {
+ return "", errors.Errorf("could not find any cgroup in %q", procPath)
+ }
+
+ return cgroupPath, nil
}
// RootFsSize returns the root FS size of the container
@@ -1074,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
}
}
@@ -1088,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_api.go b/libpod/container_api.go
index a9808a30e..6a7ddc421 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -714,3 +714,17 @@ func (c *Container) Restore(ctx context.Context, options ContainerCheckpointOpti
defer c.newContainerEvent(events.Restore)
return c.restore(ctx, options)
}
+
+// Indicate whether or not the container should restart
+func (c *Container) ShouldRestart(ctx context.Context) bool {
+ logrus.Debugf("Checking if container %s should restart", c.ID())
+ if !c.batched {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if err := c.syncContainer(); err != nil {
+ return false
+ }
+ }
+ return c.shouldRestart()
+}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 108954bad..b6a3244ea 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -206,37 +206,39 @@ func (c *Container) handleExitFile(exitFile string, fi os.FileInfo) error {
return nil
}
-// Handle container restart policy.
-// This is called when a container has exited, and was not explicitly stopped by
-// an API call to stop the container or pod it is in.
-func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr error) {
- // If we did not get a restart policy match, exit immediately.
+func (c *Container) shouldRestart() bool {
+ // If we did not get a restart policy match, return false
// Do the same if we're not a policy that restarts.
if !c.state.RestartPolicyMatch ||
c.config.RestartPolicy == RestartPolicyNo ||
c.config.RestartPolicy == RestartPolicyNone {
- return false, nil
+ return false
}
// If we're RestartPolicyOnFailure, we need to check retries and exit
// code.
if c.config.RestartPolicy == RestartPolicyOnFailure {
if c.state.ExitCode == 0 {
- return false, nil
+ return false
}
// If we don't have a max retries set, continue
if c.config.RestartRetries > 0 {
- if c.state.RestartCount < c.config.RestartRetries {
- logrus.Debugf("Container %s restart policy trigger: on retry %d (of %d)",
- c.ID(), c.state.RestartCount, c.config.RestartRetries)
- } else {
- logrus.Debugf("Container %s restart policy trigger: retries exhausted", c.ID())
- return false, nil
+ if c.state.RestartCount >= c.config.RestartRetries {
+ return false
}
}
}
+ return true
+}
+// Handle container restart policy.
+// This is called when a container has exited, and was not explicitly stopped by
+// an API call to stop the container or pod it is in.
+func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr error) {
+ if !c.shouldRestart() {
+ return false, nil
+ }
logrus.Debugf("Restarting container %s due to restart policy %s", c.ID(), c.config.RestartPolicy)
// Need to check if dependencies are alive.
@@ -641,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/healthcheck_linux.go b/libpod/healthcheck_linux.go
index b0f1ff35d..0ad15da09 100644
--- a/libpod/healthcheck_linux.go
+++ b/libpod/healthcheck_linux.go
@@ -26,6 +26,10 @@ func (c *Container) createTimer() error {
if rootless.IsRootless() {
cmd = append(cmd, "--user")
}
+ path := os.Getenv("PATH")
+ if path != "" {
+ cmd = append(cmd, "--setenv=PATH="+path)
+ }
cmd = append(cmd, "--unit", c.ID(), fmt.Sprintf("--on-unit-inactive=%s", c.HealthCheckConfig().Interval.String()), "--timer-property=AccuracySec=1s", podman, "healthcheck", "run", c.ID())
conn, err := systemd.ConnectToDBUS()
diff --git a/libpod/image/manifests.go b/libpod/image/manifests.go
index 59678fdb2..14f7c2f83 100644
--- a/libpod/image/manifests.go
+++ b/libpod/image/manifests.go
@@ -2,13 +2,14 @@ package image
import (
"context"
+ "fmt"
"github.com/containers/buildah/manifests"
+ "github.com/containers/image/v5/docker"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
- "github.com/pkg/errors"
)
// Options for adding a manifest
@@ -69,19 +70,10 @@ func CreateManifestList(rt *Runtime, systemContext types.SystemContext, names []
list := manifests.Create()
opts := ManifestAddOpts{Images: names, All: all}
for _, img := range imgs {
- var ref types.ImageReference
- newImage, err := rt.NewFromLocal(img)
- if err == nil {
- ir, err := newImage.toImageRef(context.Background())
- if err != nil {
- return "", err
- }
- if ir == nil {
- return "", errors.New("unable to convert image to ImageReference")
- }
- ref = ir.Reference()
- } else {
- ref, err = alltransports.ParseImageName(img)
+ ref, err := alltransports.ParseImageName(img)
+ if err != nil {
+ dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
+ ref, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, img))
if err != nil {
return "", err
}
@@ -134,18 +126,10 @@ func addManifestToList(ref types.ImageReference, list manifests.List, systemCont
// AddManifest adds a manifest to a given manifest list.
func (i *Image) AddManifest(systemContext types.SystemContext, opts ManifestAddOpts) (string, error) {
- var (
- ref types.ImageReference
- )
- newImage, err := i.imageruntime.NewFromLocal(opts.Images[0])
- if err == nil {
- ir, err := newImage.toImageRef(context.Background())
- if err != nil {
- return "", err
- }
- ref = ir.Reference()
- } else {
- ref, err = alltransports.ParseImageName(opts.Images[0])
+ ref, err := alltransports.ParseImageName(opts.Images[0])
+ if err != nil {
+ dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name())
+ ref, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, opts.Images[0]))
if err != nil {
return "", err
}
diff --git a/libpod/network/config.go b/libpod/network/config.go
index ce8a4446c..ce351129e 100644
--- a/libpod/network/config.go
+++ b/libpod/network/config.go
@@ -129,6 +129,16 @@ func (f FirewallConfig) Bytes() ([]byte, error) {
return json.MarshalIndent(f, "", "\t")
}
+// TuningConfig describes the tuning plugin
+type TuningConfig struct {
+ PluginType string `json:"type"`
+}
+
+// Bytes outputs the configuration as []byte
+func (f TuningConfig) Bytes() ([]byte, error) {
+ return json.MarshalIndent(f, "", "\t")
+}
+
// DNSNameConfig describes the dns container name resolution plugin config
type DNSNameConfig struct {
PluginType string `json:"type"`
diff --git a/libpod/network/create.go b/libpod/network/create.go
index 387f4fcd3..7e4fc574a 100644
--- a/libpod/network/create.go
+++ b/libpod/network/create.go
@@ -176,6 +176,7 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon
plugins = append(plugins, bridge)
plugins = append(plugins, NewPortMapPlugin())
plugins = append(plugins, NewFirewallPlugin())
+ plugins = append(plugins, NewTuningPlugin())
// if we find the dnsname plugin or are rootless, we add configuration for it
// the rootless-cni-infra container has the dnsname plugin always installed
if (HasDNSNamePlugin(runtimeConfig.Network.CNIPluginDirs) || rootless.IsRootless()) && !options.DisableDNS {
diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go
index 111f1715c..ee9adce14 100644
--- a/libpod/network/netconflist.go
+++ b/libpod/network/netconflist.go
@@ -119,6 +119,13 @@ func NewFirewallPlugin() FirewallConfig {
}
}
+// NewTuningPlugin creates a generic tuning section
+func NewTuningPlugin() TuningConfig {
+ return TuningConfig{
+ PluginType: "tuning",
+ }
+}
+
// NewDNSNamePlugin creates the dnsname config with a given
// domainname
func NewDNSNamePlugin(domainName string) DNSNameConfig {
diff --git a/libpod/network/subnet.go b/libpod/network/subnet.go
index 90f0cdfce..120038e57 100644
--- a/libpod/network/subnet.go
+++ b/libpod/network/subnet.go
@@ -54,14 +54,10 @@ func LastIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
ones, bits := cidr.Mask.Size()
if ones == bits {
- return FirstIPInSubnet(cidr)
+ return cidr.IP, nil
}
- hostStart := ones / 8
- // Handle the first host byte
- cidr.IP[hostStart] |= 0xff & cidr.Mask[hostStart]
- // Fill the rest with ones
- for i := hostStart; i < len(cidr.IP); i++ {
- cidr.IP[i] = 0xff
+ for i := range cidr.IP {
+ cidr.IP[i] = cidr.IP[i] | ^cidr.Mask[i]
}
return cidr.IP, nil
}
@@ -73,6 +69,10 @@ func FirstIPInSubnet(addr *net.IPNet) (net.IP, error) { //nolint:interfacer
if err != nil {
return nil, err
}
+ ones, bits := cidr.Mask.Size()
+ if ones == bits {
+ return cidr.IP, nil
+ }
cidr.IP[len(cidr.IP)-1]++
return cidr.IP, nil
}
diff --git a/libpod/network/subnet_test.go b/libpod/network/subnet_test.go
index 917c3be88..55b2443bd 100644
--- a/libpod/network/subnet_test.go
+++ b/libpod/network/subnet_test.go
@@ -33,3 +33,65 @@ func TestNextSubnet(t *testing.T) {
})
}
}
+
+func TestFirstIPInSubnet(t *testing.T) {
+ tests := []struct {
+ name string
+ args *net.IPNet
+ want net.IP
+ wantErr bool
+ }{
+ {"class b", parseCIDR("192.168.0.0/16"), net.ParseIP("192.168.0.1"), false},
+ {"class c", parseCIDR("192.168.1.0/24"), net.ParseIP("192.168.1.1"), false},
+ {"cidr /23", parseCIDR("192.168.0.0/23"), net.ParseIP("192.168.0.1"), false},
+ {"cidr /25", parseCIDR("192.168.1.0/25"), net.ParseIP("192.168.1.1"), false},
+ {"cidr /26", parseCIDR("172.16.1.128/26"), net.ParseIP("172.16.1.129"), false},
+ {"class a", parseCIDR("10.0.0.0/8"), net.ParseIP("10.0.0.1"), false},
+ {"cidr /32", parseCIDR("192.168.255.4/32"), net.ParseIP("192.168.255.4"), false},
+ {"cidr /31", parseCIDR("192.168.255.4/31"), net.ParseIP("192.168.255.5"), false},
+ }
+ for _, tt := range tests {
+ test := tt
+ t.Run(test.name, func(t *testing.T) {
+ got, err := FirstIPInSubnet(test.args)
+ if (err != nil) != test.wantErr {
+ t.Errorf("FirstIPInSubnet() error = %v, wantErr %v", err, test.wantErr)
+ return
+ }
+ if !got.Equal(test.want) {
+ t.Errorf("FirstIPInSubnet() got = %v, want %v", got, test.want)
+ }
+ })
+ }
+}
+
+func TestLastIPInSubnet(t *testing.T) {
+ tests := []struct {
+ name string
+ args *net.IPNet
+ want net.IP
+ wantErr bool
+ }{
+ {"class b", parseCIDR("192.168.0.0/16"), net.ParseIP("192.168.255.255"), false},
+ {"class c", parseCIDR("192.168.1.0/24"), net.ParseIP("192.168.1.255"), false},
+ {"cidr /23", parseCIDR("192.168.0.0/23"), net.ParseIP("192.168.1.255"), false},
+ {"cidr /25", parseCIDR("192.168.1.0/25"), net.ParseIP("192.168.1.127"), false},
+ {"cidr /26", parseCIDR("172.16.1.128/26"), net.ParseIP("172.16.1.191"), false},
+ {"class a", parseCIDR("10.0.0.0/8"), net.ParseIP("10.255.255.255"), false},
+ {"cidr /32", parseCIDR("192.168.255.4/32"), net.ParseIP("192.168.255.4"), false},
+ {"cidr /31", parseCIDR("192.168.255.4/31"), net.ParseIP("192.168.255.5"), false},
+ }
+ for _, tt := range tests {
+ test := tt
+ t.Run(test.name, func(t *testing.T) {
+ got, err := LastIPInSubnet(test.args)
+ if (err != nil) != test.wantErr {
+ t.Errorf("LastIPInSubnet() error = %v, wantErr %v", err, test.wantErr)
+ return
+ }
+ if !got.Equal(test.want) {
+ t.Errorf("LastIPInSubnet() got = %v, want %v", got, test.want)
+ }
+ })
+ }
+}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 8dce7c9fe..4e7ffaf81 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,9 +898,9 @@ 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))
+ return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI network(s) %v, but have information on %d network(s)", len(networks), networks, len(c.state.NetworkStatus))
}
settings.Networks = make(map[string]*define.InspectAdditionalNetwork)
@@ -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
}
@@ -1139,8 +1144,8 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
// build a list of network names so we can sort and
// get the new name's index
var networkNames []string
- for netName := range networks {
- networkNames = append(networkNames, netName)
+ for name := range networks {
+ networkNames = append(networkNames, name)
}
networkNames = append(networkNames, netName)
// sort
@@ -1152,6 +1157,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
// populate network status
copy(networkStatus[index+1:], networkStatus[index:])
networkStatus[index] = networkResults[0]
+ c.state.NetworkStatus = networkStatus
}
c.newNetworkEvent(events.NetworkConnect, netName)
return c.save()
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..5886455e7 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
@@ -318,8 +321,8 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
cb := types.ContainerJSONBase{
ID: l.ID(),
Created: l.CreatedTime().Format(time.RFC3339Nano),
- Path: "",
- Args: nil,
+ Path: inspect.Path,
+ Args: inspect.Args,
State: &state,
Image: imageName,
ResolvConfPath: inspect.ResolvConfPath,
@@ -328,7 +331,7 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
LogPath: l.LogPath(),
Node: nil,
Name: fmt.Sprintf("/%s", l.Name()),
- RestartCount: 0,
+ RestartCount: int(inspect.RestartCount),
Driver: inspect.Driver,
Platform: "linux",
MountLabel: inspect.MountLabel,
@@ -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/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go
index 4efe770b3..729639928 100644
--- a/pkg/api/handlers/compat/containers_create.go
+++ b/pkg/api/handlers/compat/containers_create.go
@@ -19,7 +19,6 @@ import (
func CreateContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
- input := handlers.CreateContainerConfig{}
query := struct {
Name string `schema:"name"`
}{
@@ -30,11 +29,15 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
+
+ // compatible configuration
+ body := handlers.CreateContainerConfig{}
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
- if len(input.HostConfig.Links) > 0 {
+
+ if len(body.HostConfig.Links) > 0 {
utils.Error(w, utils.ErrLinkNotSupport.Error(), http.StatusBadRequest, errors.Wrapf(utils.ErrLinkNotSupport, "bad parameter"))
return
}
@@ -43,7 +46,7 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "unable to obtain runtime config", http.StatusInternalServerError, errors.Wrap(err, "unable to get runtime config"))
}
- newImage, err := runtime.ImageRuntime().NewFromLocal(input.Image)
+ newImage, err := runtime.ImageRuntime().NewFromLocal(body.Config.Image)
if err != nil {
if errors.Cause(err) == define.ErrNoSuchImage {
utils.Error(w, "No such image", http.StatusNotFound, err)
@@ -54,11 +57,8 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
return
}
- // Add the container name to the input struct
- input.Name = query.Name
-
- // Take input structure and convert to cliopts
- cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(input, rtc.Engine.CgroupManager)
+ // Take body structure and convert to cliopts
+ cliOpts, args, err := common.ContainerCreateToContainerCLIOpts(body, rtc.Engine.CgroupManager)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "make cli opts()"))
return
@@ -69,6 +69,9 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) {
return
}
+ // Override the container name in the body struct
+ body.Name = query.Name
+
ic := abi.ContainerEngine{Libpod: runtime}
report, err := ic.ContainerCreate(r.Context(), sg)
if err != nil {
diff --git a/pkg/api/handlers/compat/info.go b/pkg/api/handlers/compat/info.go
index 2bb165522..4b3a390f1 100644
--- a/pkg/api/handlers/compat/info.go
+++ b/pkg/api/handlers/compat/info.go
@@ -17,6 +17,7 @@ import (
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/rootless"
docker "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/google/uuid"
"github.com/pkg/errors"
@@ -103,7 +104,7 @@ func GetInfo(w http.ResponseWriter, r *http.Request) {
PidsLimit: sysInfo.PidsLimit,
Plugins: docker.PluginsInfo{},
ProductLicense: "Apache-2.0",
- RegistryConfig: nil,
+ RegistryConfig: new(registry.ServiceConfig),
RuncCommit: docker.Commit{},
Runtimes: getRuntimes(configInfo),
SecurityOptions: getSecOpts(sysInfo),
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 7e6481321..14eb44831 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -344,3 +344,27 @@ func InitContainer(w http.ResponseWriter, r *http.Request) {
}
utils.WriteResponse(w, http.StatusNoContent, "")
}
+
+func ShouldRestart(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ // Now use the ABI implementation to prevent us from having duplicate
+ // code.
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+
+ name := utils.GetName(r)
+ report, err := containerEngine.ShouldRestart(r.Context(), name)
+ if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ utils.InternalServerError(w, err)
+ return
+
+ }
+ if report.Value {
+ utils.WriteResponse(w, http.StatusNoContent, "")
+ } else {
+ utils.ContainerNotFound(w, name, define.ErrNoSuchCtr)
+ }
+}
diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go
index 6bb5f5101..40cf16807 100644
--- a/pkg/api/handlers/types.go
+++ b/pkg/api/handlers/types.go
@@ -110,11 +110,12 @@ type ContainerWaitOKBody struct {
}
}
+// CreateContainerConfig used when compatible endpoint creates a container
type CreateContainerConfig struct {
- Name string
- dockerContainer.Config
- HostConfig dockerContainer.HostConfig
- NetworkingConfig dockerNetwork.NetworkingConfig
+ Name string // container name
+ dockerContainer.Config // desired container configuration
+ HostConfig dockerContainer.HostConfig // host dependent configuration for container
+ NetworkingConfig dockerNetwork.NetworkingConfig // network configuration for container
}
// swagger:model IDResponse
@@ -253,7 +254,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
// StdinOnce: false,
Env: info.Config.Env,
Cmd: info.Config.Cmd,
- //Healthcheck: l.ImageData.HealthCheck,
+ // Healthcheck: l.ImageData.HealthCheck,
// ArgsEscaped: false,
// Image: "",
Volumes: info.Config.Volumes,
@@ -261,7 +262,7 @@ func ImageDataToImageInspect(ctx context.Context, l *libpodImage.Image) (*ImageI
Entrypoint: info.Config.Entrypoint,
// NetworkDisabled: false,
// MacAddress: "",
- //OnBuild: info.Config.OnBuild,
+ // OnBuild: info.Config.OnBuild,
Labels: info.Labels,
StopSignal: info.Config.StopSignal,
// StopTimeout: nil,
diff --git a/pkg/api/server/handler_api.go b/pkg/api/server/handler_api.go
index 28f5a0b42..1d0ddb457 100644
--- a/pkg/api/server/handler_api.go
+++ b/pkg/api/server/handler_api.go
@@ -30,14 +30,14 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
// Wrapper to hide some boiler plate
fn := func(w http.ResponseWriter, r *http.Request) {
rid := uuid.New().String()
+ logrus.Infof("APIHandler(%s) -- %s %s BEGIN", rid, r.Method, r.URL.String())
if logrus.IsLevelEnabled(logrus.DebugLevel) {
- logrus.Debugf("APIHandler(%s) -- Method: %s URL: %s", rid, r.Method, r.URL.String())
for k, v := range r.Header {
switch auth.HeaderAuthName(k) {
case auth.XRegistryConfigHeader, auth.XRegistryAuthHeader:
- logrus.Debugf("APIHandler(%s) -- Header: %s: <hidden>", rid, k)
+ logrus.Debugf("APIHandler(%s) -- Header: %s=<hidden>", rid, k)
default:
- logrus.Debugf("APIHandler(%s) -- Header: %s: %v", rid, k, v)
+ logrus.Debugf("APIHandler(%s) -- Header: %s=%v", rid, k, v)
}
}
}
@@ -63,6 +63,7 @@ func (s *APIServer) APIHandler(h http.HandlerFunc) http.HandlerFunc {
w.Header().Set("Server", "Libpod/"+lv+" ("+runtime.GOOS+")")
h(w, r)
+ logrus.Debugf("APIHandler(%s) -- %s %s END", rid, r.Method, r.URL.String())
}
fn(w, r)
}
diff --git a/pkg/api/server/listener_api.go b/pkg/api/server/listener_api.go
index 4984216b8..2d02df7dc 100644
--- a/pkg/api/server/listener_api.go
+++ b/pkg/api/server/listener_api.go
@@ -27,5 +27,6 @@ func ListenUnix(network string, path string) (net.Listener, error) {
if err != nil {
return nil, errors.Wrapf(err, "net.Listen(%s, %s) failed to report the failure to create socket", network, path)
}
+
return listener, nil
}
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 64008767b..09b6079e4 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -51,10 +51,7 @@ func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
}
// NewServerWithSettings will create and configure a new API server using provided settings
-func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (
- *APIServer,
- error,
-) {
+func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
return newServer(runtime, duration, listener)
}
@@ -75,6 +72,7 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
listener = &listeners[0]
}
+ logrus.Infof("API server listening on %q", (*listener).Addr())
router := mux.NewRouter().UseEncodedPath()
idle := idle.NewTracker(duration)
diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go
index b5cd2128b..4331ae6c2 100644
--- a/pkg/bindings/containers/containers.go
+++ b/pkg/bindings/containers/containers.go
@@ -390,3 +390,15 @@ func ContainerInit(ctx context.Context, nameOrID string) error {
}
return response.Process(nil)
}
+
+func ShouldRestart(ctx context.Context, nameOrID string) (bool, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return false, err
+ }
+ response, err := conn.DoRequest(nil, http.MethodPost, "/containers/%s/shouldrestart", nil, nil, nameOrID)
+ if err != nil {
+ return false, err
+ }
+ return response.IsSuccess(), nil
+}
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index 101542a98..ab545d882 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 // nolint
+ RepoTags []string `json:",omitempty"`
+ Created int64
Size int64 `json:",omitempty"`
SharedSize int `json:",omitempty"`
VirtualSize int64 `json:",omitempty"`
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 4b69ac74e..ff4277a2e 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -911,7 +911,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
} else {
report.ExitCode = int(ecode)
}
- if opts.Rm {
+ if opts.Rm && !ctr.ShouldRestart(ctx) {
if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr ||
errors.Cause(err) == define.ErrCtrRemoved {
@@ -992,7 +992,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
return []*entities.ContainerCleanupReport{}, nil
}
- if options.Remove {
+ if options.Remove && !ctr.ShouldRestart(ctx) {
err = ic.Libpod.RemoveContainer(ctx, ctr, false, true)
if err != nil {
report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
@@ -1015,6 +1015,7 @@ func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []st
_, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
report.RmiErr = err
}
+
reports = append(reports, &report)
}
return reports, nil
@@ -1314,3 +1315,13 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
return statsChan, nil
}
+
+// ShouldRestart returns whether the container should be restarted
+func (ic *ContainerEngine) ShouldRestart(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
+ ctr, err := ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ return &entities.BoolReport{Value: ctr.ShouldRestart(ctx)}, nil
+}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 8066e1c00..1aa5afbe7 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -595,12 +595,20 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
// Defer the removal, so we can return early if needed and
// de-spaghetti the code.
defer func() {
- if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
- if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
- errorhandling.Contains(err, define.ErrCtrRemoved) {
- logrus.Warnf("Container %s does not exist: %v", con.ID, err)
- } else {
- logrus.Errorf("Error removing container %s: %v", con.ID, err)
+ shouldRestart, err := containers.ShouldRestart(ic.ClientCxt, con.ID)
+ if err != nil {
+ logrus.Errorf("Failed to check if %s should restart: %v", con.ID, err)
+ return
+ }
+
+ if !shouldRestart {
+ if err := containers.Remove(ic.ClientCxt, con.ID, bindings.PFalse, bindings.PTrue); err != nil {
+ if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
+ errorhandling.Contains(err, define.ErrCtrRemoved) {
+ logrus.Warnf("Container %s does not exist: %v", con.ID, err)
+ } else {
+ logrus.Errorf("Error removing container %s: %v", con.ID, err)
+ }
}
}
}()
@@ -737,3 +745,8 @@ func (ic *ContainerEngine) ContainerStats(ctx context.Context, namesOrIds []stri
}
return containers.Stats(ic.ClientCxt, namesOrIds, &options.Stream)
}
+
+// ShouldRestart reports back whether the containre will restart
+func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, error) {
+ return containers.ShouldRestart(ic.ClientCxt, id)
+}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index c049e64cf..45a374216 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -111,7 +111,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, errors.Wrap(err, "invalid config provided")
}
- finalMounts, finalVolumes, err := finalizeMounts(ctx, s, rt, rtc, newImage)
+ finalMounts, finalVolumes, finalOverlays, err := finalizeMounts(ctx, s, rt, rtc, newImage)
if err != nil {
return nil, err
}
@@ -121,7 +121,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return nil, err
}
- opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, newImage, command)
+ opts, err := createContainerOptions(ctx, rt, s, pod, finalVolumes, finalOverlays, newImage, command)
if err != nil {
return nil, err
}
@@ -144,7 +144,7 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
return rt.NewContainer(ctx, runtimeSpec, options...)
}
-func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) {
+func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGenerator, pod *libpod.Pod, volumes []*specgen.NamedVolume, overlays []*specgen.OverlayVolume, img *image.Image, command []string) ([]libpod.CtrCreateOption, error) {
var options []libpod.CtrCreateOption
var err error
@@ -224,7 +224,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
for _, volume := range volumes {
destinations = append(destinations, volume.Dest)
}
- for _, overlayVolume := range s.OverlayVolumes {
+ for _, overlayVolume := range overlays {
destinations = append(destinations, overlayVolume.Destination)
}
for _, imageVolume := range s.ImageVolumes {
@@ -244,9 +244,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
options = append(options, libpod.WithNamedVolumes(vols))
}
- if len(s.OverlayVolumes) != 0 {
+ if len(overlays) != 0 {
var vols []*libpod.ContainerOverlayVolume
- for _, v := range s.OverlayVolumes {
+ for _, v := range overlays {
vols = append(vols, &libpod.ContainerOverlayVolume{
Dest: v.Destination,
Source: v.Source,
diff --git a/pkg/specgen/generate/storage.go b/pkg/specgen/generate/storage.go
index b225f79ee..331a5c5bf 100644
--- a/pkg/specgen/generate/storage.go
+++ b/pkg/specgen/generate/storage.go
@@ -33,17 +33,17 @@ var (
)
// Produce final mounts and named volumes for a container
-func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, error) {
+func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, img *image.Image) ([]spec.Mount, []*specgen.NamedVolume, []*specgen.OverlayVolume, error) {
// Get image volumes
baseMounts, baseVolumes, err := getImageVolumes(ctx, img, s)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
// Get volumes-from mounts
volFromMounts, volFromVolumes, err := getVolumesFrom(s.VolumesFrom, rt)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
// Supersede from --volumes-from.
@@ -57,19 +57,53 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
// Need to make map forms of specgen mounts/volumes.
unifiedMounts := map[string]spec.Mount{}
unifiedVolumes := map[string]*specgen.NamedVolume{}
+ unifiedOverlays := map[string]*specgen.OverlayVolume{}
+
+ // Need to make map forms of specgen mounts/volumes.
+ commonMounts, commonVolumes, commonOverlayVolumes, err := specgen.GenVolumeMounts(rtc.Volumes())
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
for _, m := range s.Mounts {
if _, ok := unifiedMounts[m.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified mounts - multiple mounts at %q", m.Destination)
}
unifiedMounts[m.Destination] = m
}
+
+ for _, m := range commonMounts {
+ if _, ok := unifiedMounts[m.Destination]; !ok {
+ unifiedMounts[m.Destination] = m
+ }
+ }
+
for _, v := range s.Volumes {
if _, ok := unifiedVolumes[v.Dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Dest)
}
unifiedVolumes[v.Dest] = v
}
+ for _, v := range commonVolumes {
+ if _, ok := unifiedVolumes[v.Dest]; !ok {
+ unifiedVolumes[v.Dest] = v
+ }
+ }
+
+ for _, v := range s.OverlayVolumes {
+ if _, ok := unifiedOverlays[v.Destination]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict in specified volumes - multiple volumes at %q", v.Destination)
+ }
+ unifiedOverlays[v.Destination] = v
+ }
+
+ for _, v := range commonOverlayVolumes {
+ if _, ok := unifiedOverlays[v.Destination]; ok {
+ unifiedOverlays[v.Destination] = v
+ }
+ }
+
// If requested, add container init binary
if s.Init {
initPath := s.InitPath
@@ -78,10 +112,10 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
}
initMount, err := addContainerInitBinary(s, initPath)
if err != nil {
- return nil, nil, err
+ return nil, nil, nil, err
}
if _, ok := unifiedMounts[initMount.Destination]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict with mount added by --init to %q", initMount.Destination)
}
unifiedMounts[initMount.Destination] = initMount
}
@@ -115,12 +149,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
// Check for conflicts between named volumes and mounts
for dest := range baseMounts {
if _, ok := baseVolumes[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
}
}
for dest := range baseVolumes {
if _, ok := baseMounts[dest]; ok {
- return nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, "conflict at mount destination %v", dest)
}
}
// Final step: maps to arrays
@@ -129,7 +163,7 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
if mount.Type == TypeBind {
absSrc, err := filepath.Abs(mount.Source)
if err != nil {
- return nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
+ return nil, nil, nil, errors.Wrapf(err, "error getting absolute path of %s", mount.Source)
}
mount.Source = absSrc
}
@@ -140,7 +174,12 @@ func finalizeMounts(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Ru
finalVolumes = append(finalVolumes, volume)
}
- return finalMounts, finalVolumes, nil
+ finalOverlays := make([]*specgen.OverlayVolume, 0, len(unifiedOverlays))
+ for _, volume := range unifiedOverlays {
+ finalOverlays = append(finalOverlays, volume)
+ }
+
+ return finalMounts, finalVolumes, finalOverlays, nil
}
// Get image volumes from the given image
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/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 0a9a16ea7..fad2406e5 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -1,13 +1,13 @@
package specgen
import (
- "errors"
"net"
"syscall"
"github.com/containers/image/v5/manifest"
"github.com/containers/storage"
spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
)
// LogConfig describes the logging characteristics for a container
@@ -459,42 +459,6 @@ type SpecGenerator struct {
ContainerHealthCheckConfig
}
-// NamedVolume holds information about a named volume that will be mounted into
-// the container.
-type NamedVolume struct {
- // Name is the name of the named volume to be mounted. May be empty.
- // If empty, a new named volume with a pseudorandomly generated name
- // will be mounted at the given destination.
- Name string
- // Destination to mount the named volume within the container. Must be
- // an absolute path. Path will be created if it does not exist.
- Dest string
- // Options are options that the named volume will be mounted with.
- Options []string
-}
-
-// OverlayVolume holds information about a overlay volume that will be mounted into
-// the container.
-type OverlayVolume struct {
- // Destination is the absolute path where the mount will be placed in the container.
- Destination string `json:"destination"`
- // Source specifies the source path of the mount.
- Source string `json:"source,omitempty"`
-}
-
-// ImageVolume is a volume based on a container image. The container image is
-// first mounted on the host and is then bind-mounted into the container. An
-// ImageVolume is always mounted read only.
-type ImageVolume struct {
- // Source is the source of the image volume. The image can be referred
- // to by name and by ID.
- Source string
- // Destination is the absolute path of the mount in the container.
- Destination string
- // ReadWrite sets the volume writable.
- ReadWrite bool
-}
-
// PortMapping is one or more ports that will be mapped into the container.
type PortMapping struct {
// HostIP is the IP that we will bind to on the host.
diff --git a/pkg/specgen/volumes.go b/pkg/specgen/volumes.go
new file mode 100644
index 000000000..1178f9960
--- /dev/null
+++ b/pkg/specgen/volumes.go
@@ -0,0 +1,149 @@
+package specgen
+
+import (
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/buildah/pkg/parse"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// NamedVolume holds information about a named volume that will be mounted into
+// the container.
+type NamedVolume struct {
+ // Name is the name of the named volume to be mounted. May be empty.
+ // If empty, a new named volume with a pseudorandomly generated name
+ // will be mounted at the given destination.
+ Name string
+ // Destination to mount the named volume within the container. Must be
+ // an absolute path. Path will be created if it does not exist.
+ Dest string
+ // Options are options that the named volume will be mounted with.
+ Options []string
+}
+
+// OverlayVolume holds information about a overlay volume that will be mounted into
+// the container.
+type OverlayVolume struct {
+ // Destination is the absolute path where the mount will be placed in the container.
+ Destination string `json:"destination"`
+ // Source specifies the source path of the mount.
+ Source string `json:"source,omitempty"`
+}
+
+// ImageVolume is a volume based on a container image. The container image is
+// first mounted on the host and is then bind-mounted into the container. An
+// ImageVolume is always mounted read only.
+type ImageVolume struct {
+ // Source is the source of the image volume. The image can be referred
+ // to by name and by ID.
+ Source string
+ // Destination is the absolute path of the mount in the container.
+ Destination string
+ // ReadWrite sets the volume writable.
+ ReadWrite bool
+}
+
+// GenVolumeMounts parses user input into mounts, volumes and overlay volumes
+func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*NamedVolume, map[string]*OverlayVolume, error) {
+ errDuplicateDest := errors.Errorf("duplicate mount destination")
+
+ mounts := make(map[string]spec.Mount)
+ volumes := make(map[string]*NamedVolume)
+ overlayVolumes := make(map[string]*OverlayVolume)
+
+ volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]")
+
+ for _, vol := range volumeFlag {
+ var (
+ options []string
+ src string
+ dest string
+ err error
+ )
+
+ splitVol := strings.Split(vol, ":")
+ if len(splitVol) > 3 {
+ return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol)
+ }
+
+ src = splitVol[0]
+ if len(splitVol) == 1 {
+ // This is an anonymous named volume. Only thing given
+ // is destination.
+ // Name/source will be blank, and populated by libpod.
+ src = ""
+ dest = splitVol[0]
+ } else if len(splitVol) > 1 {
+ dest = splitVol[1]
+ }
+ if len(splitVol) > 2 {
+ if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil {
+ return nil, nil, nil, err
+ }
+ }
+
+ // Do not check source dir for anonymous volumes
+ if len(splitVol) > 1 {
+ if err := parse.ValidateVolumeHostDir(src); err != nil {
+ return nil, nil, nil, err
+ }
+ }
+ if err := parse.ValidateVolumeCtrDir(dest); err != nil {
+ return nil, nil, nil, err
+ }
+
+ cleanDest := filepath.Clean(dest)
+
+ if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") {
+ // This is not a named volume
+ overlayFlag := false
+ for _, o := range options {
+ if o == "O" {
+ overlayFlag = true
+ if len(options) > 1 {
+ return nil, nil, nil, errors.New("can't use 'O' with other options")
+ }
+ }
+ }
+ if overlayFlag {
+ // This is a overlay volume
+ newOverlayVol := new(OverlayVolume)
+ newOverlayVol.Destination = cleanDest
+ newOverlayVol.Source = src
+ if _, ok := overlayVolumes[newOverlayVol.Destination]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination)
+ }
+ overlayVolumes[newOverlayVol.Destination] = newOverlayVol
+ } else {
+ newMount := spec.Mount{
+ Destination: cleanDest,
+ Type: "bind",
+ Source: src,
+ Options: options,
+ }
+ if _, ok := mounts[newMount.Destination]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination)
+ }
+ mounts[newMount.Destination] = newMount
+ }
+ } else {
+ // This is a named volume
+ newNamedVol := new(NamedVolume)
+ newNamedVol.Name = src
+ newNamedVol.Dest = cleanDest
+ newNamedVol.Options = options
+
+ if _, ok := volumes[newNamedVol.Dest]; ok {
+ return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest)
+ }
+ volumes[newNamedVol.Dest] = newNamedVol
+ }
+
+ logrus.Debugf("User mount %s:%s options %v", src, dest, options)
+ }
+
+ return mounts, volumes, overlayVolumes, nil
+}
diff --git a/test/apiv2/rest_api/__init__.py b/test/apiv2/rest_api/__init__.py
index 8100a4df5..db0257f03 100644
--- a/test/apiv2/rest_api/__init__.py
+++ b/test/apiv2/rest_api/__init__.py
@@ -16,19 +16,18 @@ class Podman(object):
binary = os.getenv("PODMAN", "bin/podman")
self.cmd = [binary, "--storage-driver=vfs"]
- cgroupfs = os.getenv("CGROUP_MANAGER", "cgroupfs")
+ cgroupfs = os.getenv("CGROUP_MANAGER", "systemd")
self.cmd.append(f"--cgroup-manager={cgroupfs}")
if os.getenv("DEBUG"):
self.cmd.append("--log-level=debug")
+ self.cmd.append("--syslog=true")
self.anchor_directory = tempfile.mkdtemp(prefix="podman_restapi_")
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
- os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(
- self.anchor_directory, "registry.conf"
- )
+ os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(self.anchor_directory, "registry.conf")
p = configparser.ConfigParser()
p.read_dict(
{
@@ -40,14 +39,10 @@ class Podman(object):
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
p.write(w)
- os.environ["CNI_CONFIG_PATH"] = os.path.join(
- self.anchor_directory, "cni", "net.d"
- )
+ os.environ["CNI_CONFIG_PATH"] = os.path.join(self.anchor_directory, "cni", "net.d")
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
- cni_cfg = os.path.join(
- os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
- )
+ cni_cfg = os.path.join(os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist")
# json decoded and encoded to ensure legal json
buf = json.loads(
"""
diff --git a/test/apiv2/rest_api/test_rest_v2_0_0.py b/test/apiv2/rest_api/test_rest_v2_0_0.py
index 49e18f063..52348d4f4 100644
--- a/test/apiv2/rest_api/test_rest_v2_0_0.py
+++ b/test/apiv2/rest_api/test_rest_v2_0_0.py
@@ -61,9 +61,7 @@ class TestApi(unittest.TestCase):
super().setUpClass()
TestApi.podman = Podman()
- TestApi.service = TestApi.podman.open(
- "system", "service", "tcp:localhost:8080", "--time=0"
- )
+ TestApi.service = TestApi.podman.open("system", "service", "tcp:localhost:8080", "--time=0")
# give the service some time to be ready...
time.sleep(2)
@@ -165,11 +163,71 @@ class TestApi(unittest.TestCase):
r = requests.get(_url(ctnr("/containers/{}/logs?stdout=true")))
self.assertEqual(r.status_code, 200, r.text)
- def test_post_create_compat(self):
+ # TODO Need to support Docker-py order of network/container creates
+ def test_post_create_compat_connect(self):
"""Create network and container then connect to network"""
- net = requests.post(
- PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"}
+ net_default = requests.post(
+ PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestDefaultNetwork"}
+ )
+ self.assertEqual(net_default.status_code, 201, net_default.text)
+
+ create = requests.post(
+ PODMAN_URL + "/v1.40/containers/create?name=postCreate",
+ json={
+ "Cmd": ["top"],
+ "Image": "alpine:latest",
+ "NetworkDisabled": False,
+ # FIXME adding these 2 lines cause: (This is sampled from docker-py)
+ # "network already exists","message":"container
+ # 01306e499df5441560d70071a54342611e422a94de20865add50a9565fd79fb9 is already connected to CNI network \"TestDefaultNetwork\": network already exists"
+ # "HostConfig": {"NetworkMode": "TestDefaultNetwork"},
+ # "NetworkingConfig": {"EndpointsConfig": {"TestDefaultNetwork": None}},
+ # FIXME These two lines cause:
+ # CNI network \"TestNetwork\" not found","message":"error configuring network namespace for container 369ddfa7d3211ebf1fbd5ddbff91bd33fa948858cea2985c133d6b6507546dff: CNI network \"TestNetwork\" not found"
+ # "HostConfig": {"NetworkMode": "TestNetwork"},
+ # "NetworkingConfig": {"EndpointsConfig": {"TestNetwork": None}},
+ # FIXME no networking defined cause: (note this error is from the container inspect below)
+ # "internal libpod error","message":"network inspection mismatch: asked to join 2 CNI network(s) [TestDefaultNetwork podman], but have information on 1 network(s): internal libpod error"
+ },
+ )
+ self.assertEqual(create.status_code, 201, create.text)
+ payload = json.loads(create.text)
+ self.assertIsNotNone(payload["Id"])
+
+ start = requests.post(PODMAN_URL + f"/v1.40/containers/{payload['Id']}/start")
+ self.assertEqual(start.status_code, 204, start.text)
+
+ connect = requests.post(
+ PODMAN_URL + "/v1.40/networks/TestDefaultNetwork/connect",
+ json={"Container": payload["Id"]},
+ )
+ self.assertEqual(connect.status_code, 200, connect.text)
+ self.assertEqual(connect.text, "OK\n")
+
+ inspect = requests.get(f"{PODMAN_URL}/v1.40/containers/{payload['Id']}/json")
+ self.assertEqual(inspect.status_code, 200, inspect.text)
+
+ payload = json.loads(inspect.text)
+ self.assertFalse(payload["Config"].get("NetworkDisabled", False))
+
+ self.assertEqual(
+ "TestDefaultNetwork",
+ payload["NetworkSettings"]["Networks"]["TestDefaultNetwork"]["NetworkID"],
)
+ # TODO restore this to test, when joining multiple networks possible
+ # self.assertEqual(
+ # "TestNetwork",
+ # payload["NetworkSettings"]["Networks"]["TestNetwork"]["NetworkID"],
+ # )
+ # TODO Need to support network aliases
+ # self.assertIn(
+ # "test_post_create",
+ # payload["NetworkSettings"]["Networks"]["TestNetwork"]["Aliases"],
+ # )
+
+ def test_post_create_compat(self):
+ """Create network and connect container during create"""
+ net = requests.post(PODMAN_URL + "/v1.40/networks/create", json={"Name": "TestNetwork"})
self.assertEqual(net.status_code, 201, net.text)
create = requests.post(
@@ -178,23 +236,21 @@ class TestApi(unittest.TestCase):
"Cmd": ["date"],
"Image": "alpine:latest",
"NetworkDisabled": False,
- "NetworkConfig": {
- "EndpointConfig": {"TestNetwork": {"Aliases": ["test_post_create"]}}
- },
+ "HostConfig": {"NetworkMode": "TestNetwork"},
},
)
self.assertEqual(create.status_code, 201, create.text)
payload = json.loads(create.text)
self.assertIsNotNone(payload["Id"])
- # This cannot be done until full completion of the network connect
- # stack and network disconnect stack are complete
- # connect = requests.post(
- # PODMAN_URL + "/v1.40/networks/TestNetwork/connect",
- # json={"Container": payload["Id"]},
- # )
- # self.assertEqual(connect.status_code, 200, connect.text)
- # self.assertEqual(connect.text, "OK\n")
+ inspect = requests.get(f"{PODMAN_URL}/v1.40/containers/{payload['Id']}/json")
+ self.assertEqual(inspect.status_code, 200, inspect.text)
+ payload = json.loads(inspect.text)
+ self.assertFalse(payload["Config"].get("NetworkDisabled", False))
+ self.assertEqual(
+ "TestNetwork",
+ payload["NetworkSettings"]["Networks"]["TestNetwork"]["NetworkID"],
+ )
def test_commit(self):
r = requests.post(_url(ctnr("/commit?container={}")))
diff --git a/test/apiv2/rest_api/v1_test_rest_v1_0_0.py b/test/apiv2/rest_api/v1_test_rest_v1_0_0.py
index acd6273ef..23528a246 100644
--- a/test/apiv2/rest_api/v1_test_rest_v1_0_0.py
+++ b/test/apiv2/rest_api/v1_test_rest_v1_0_0.py
@@ -84,9 +84,7 @@ class TestApi(unittest.TestCase):
print("\nService Stderr:\n" + stderr.decode("utf-8"))
if TestApi.podman.returncode > 0:
- sys.stderr.write(
- "podman exited with error code {}\n".format(TestApi.podman.returncode)
- )
+ sys.stderr.write("podman exited with error code {}\n".format(TestApi.podman.returncode))
sys.exit(2)
return super().tearDownClass()
diff --git a/test/e2e/config/containers-remote.conf b/test/e2e/config/containers-remote.conf
new file mode 100644
index 000000000..bc9eab951
--- /dev/null
+++ b/test/e2e/config/containers-remote.conf
@@ -0,0 +1,51 @@
+[containers]
+
+# A list of ulimits to be set in containers by default, specified as
+# "<ulimit name>=<soft limit>:<hard limit>", for example:
+# "nofile=1024:2048"
+# See setrlimit(2) for a list of resource names.
+# Any limit not specified here will be inherited from the process launching the
+# container engine.
+# Ulimits has limits for non privileged container engines.
+#
+default_ulimits = [
+ "nofile=100:100",
+]
+
+# Environment variable list for the conmon process; used for passing necessary
+# environment variables to conmon or the runtime.
+#
+env = [
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "foo=bar1",
+]
+
+# container engines use container separation using MAC(SELinux) labeling.
+# Flag is ignored on label disabled systems.
+#
+label = false
+
+# Size of /dev/shm. Specified as <number><unit>.
+# Unit is optional, values:
+# b (bytes), k (kilobytes), m (megabytes), or g (gigabytes).
+# If the unit is omitted, the system uses bytes.
+#
+shm_size = "202k"
+
+# List of devices. Specified as
+# "<device-on-host>:<device-on-container>:<permissions>", for example:
+# "/dev/sdc:/dev/xvdc:rwm".
+# If it is empty or commented out, only the default devices will be used
+#
+devices = []
+
+default_sysctls = [
+ "net.ipv4.ping_group_range=0 0",
+]
+
+dns_searches=[ "barfoo.com", ]
+dns_servers=[ "4.3.2.1", ]
+
+tz = "America/New_York"
+
+umask = "0022"
diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go
index 1d5be218b..906153c0f 100644
--- a/test/e2e/containers_conf_test.go
+++ b/test/e2e/containers_conf_test.go
@@ -177,6 +177,9 @@ var _ = Describe("Podman run", func() {
}
os.Setenv("CONTAINERS_CONF", conffile)
+ if IsRemote() {
+ podmanTest.RestartRemoteService()
+ }
result := podmanTest.Podman([]string{"run", ALPINE, "ls", tempdir})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
@@ -224,6 +227,17 @@ var _ = Describe("Podman run", func() {
Expect(session.LineInOuputStartsWith("search")).To(BeFalse())
})
+ It("podman run use containers.conf search domain", func() {
+ session := podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOuputStartsWith("search")).To(BeTrue())
+ Expect(session.OutputToString()).To(ContainSubstring("foobar.com"))
+
+ Expect(session.OutputToString()).To(ContainSubstring("1.2.3.4"))
+ Expect(session.OutputToString()).To(ContainSubstring("debug"))
+ })
+
It("podman run containers.conf timezone", func() {
//containers.conf timezone set to Pacific/Honolulu
session := podmanTest.Podman([]string{"run", ALPINE, "date", "+'%H %Z'"})
@@ -231,6 +245,7 @@ var _ = Describe("Podman run", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring("HST"))
})
+
It("podman run containers.conf umask", func() {
//containers.conf umask set to 0002
if !strings.Contains(podmanTest.OCIRuntime, "crun") {
@@ -243,4 +258,57 @@ var _ = Describe("Podman run", func() {
Expect(session.OutputToString()).To(Equal("0002"))
})
+ It("podman-remote test localcontainers.conf versus remote containers.conf", func() {
+ if !IsRemote() {
+ Skip("this test is only for remote")
+ }
+
+ os.Setenv("CONTAINERS_CONF", "config/containers-remote.conf")
+ // Configuration that comes from remote server
+ // env
+ session := podmanTest.Podman([]string{"run", ALPINE, "printenv", "foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(Equal("bar"))
+
+ // dns-search, server, options
+ session = podmanTest.Podman([]string{"run", ALPINE, "cat", "/etc/resolv.conf"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOuputStartsWith("search")).To(BeTrue())
+ Expect(session.OutputToString()).To(ContainSubstring("foobar.com"))
+ Expect(session.OutputToString()).To(ContainSubstring("1.2.3.4"))
+ Expect(session.OutputToString()).To(ContainSubstring("debug"))
+
+ // sysctls
+ session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "cat", "/proc/sys/net/ipv4/ping_group_range"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("1000"))
+
+ // shm-size
+ session = podmanTest.Podman([]string{"run", ALPINE, "grep", "shm", "/proc/self/mounts"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("size=200k"))
+
+ // ulimits
+ session = podmanTest.Podman([]string{"run", "--rm", fedoraMinimal, "ulimit", "-n"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("500"))
+
+ // Configuration that comes from remote client
+ // Timezone
+ session = podmanTest.Podman([]string{"run", ALPINE, "date", "+'%H %Z'"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("EST"))
+
+ // Umask
+ session = podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "umask"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(Equal("0022"))
+ })
})
diff --git a/test/e2e/create_staticmac_test.go b/test/e2e/create_staticmac_test.go
index adffdc1ca..1ac431da2 100644
--- a/test/e2e/create_staticmac_test.go
+++ b/test/e2e/create_staticmac_test.go
@@ -5,6 +5,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"
)
@@ -45,4 +46,21 @@ var _ = Describe("Podman run with --mac-address flag", func() {
Expect(result.OutputToString()).To(ContainSubstring("92:d0:c6:0a:29:34"))
}
})
+
+ It("Podman run --mac-address with custom network", func() {
+ net := "n1" + stringid.GenerateNonCryptoID()
+ session := podmanTest.Podman([]string{"network", "create", net})
+ session.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(net)
+ Expect(session.ExitCode()).To(BeZero())
+
+ result := podmanTest.Podman([]string{"run", "--network", net, "--mac-address", "92:d0:c6:00:29:34", ALPINE, "ip", "addr"})
+ result.WaitWithDefaultTimeout()
+ if rootless.IsRootless() {
+ Expect(result.ExitCode()).To(Equal(125))
+ } else {
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(ContainSubstring("92:d0:c6:00:29:34"))
+ }
+ })
})
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index c6593df34..139a90ac7 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -76,31 +76,36 @@ var _ = Describe("Podman network", func() {
Expect(session.LineInOutputContains(name)).To(BeFalse())
})
- It("podman network rm no args", func() {
- session := podmanTest.Podman([]string{"network", "rm"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).ToNot(BeZero())
- })
-
- It("podman network rm", func() {
- SkipIfRootless("FIXME: This one is definitely broken in rootless mode")
- name, path := generateNetworkConfig(podmanTest)
- defer removeConf(path)
-
- session := podmanTest.Podman([]string{"network", "ls", "--quiet"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- Expect(session.LineInOutputContains(name)).To(BeTrue())
-
- rm := podmanTest.Podman([]string{"network", "rm", name})
- rm.WaitWithDefaultTimeout()
- Expect(rm.ExitCode()).To(BeZero())
-
- results := podmanTest.Podman([]string{"network", "ls", "--quiet"})
- results.WaitWithDefaultTimeout()
- Expect(results.ExitCode()).To(Equal(0))
- Expect(results.LineInOutputContains(name)).To(BeFalse())
- })
+ rm_func := func(rm string) {
+ It(fmt.Sprintf("podman network %s no args", rm), func() {
+ session := podmanTest.Podman([]string{"network", rm})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).ToNot(BeZero())
+
+ })
+
+ It(fmt.Sprintf("podman network %s", rm), func() {
+ name, path := generateNetworkConfig(podmanTest)
+ defer removeConf(path)
+
+ session := podmanTest.Podman([]string{"network", "ls", "--quiet"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOutputContains(name)).To(BeTrue())
+
+ rm := podmanTest.Podman([]string{"network", rm, name})
+ rm.WaitWithDefaultTimeout()
+ Expect(rm.ExitCode()).To(BeZero())
+
+ results := podmanTest.Podman([]string{"network", "ls", "--quiet"})
+ results.WaitWithDefaultTimeout()
+ Expect(results.ExitCode()).To(Equal(0))
+ Expect(results.LineInOutputContains(name)).To(BeFalse())
+ })
+ }
+
+ rm_func("rm")
+ rm_func("remove")
It("podman network inspect no args", func() {
session := podmanTest.Podman([]string{"network", "inspect"})
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/ps_test.go b/test/e2e/ps_test.go
index fd08d4308..05571157c 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -44,6 +44,12 @@ var _ = Describe("Podman ps", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman container ps no containers", func() {
+ session := podmanTest.Podman([]string{"container", "ps"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
It("podman ps default", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
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"))
+ })
})
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 5ee85efb9..0d65a3e59 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -75,11 +75,9 @@ var _ = Describe("Podman run", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- // the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"
- // so the exitCode should not equal 0
session = podmanTest.Podman([]string{"run", "--rm", "--restart", "on-failure", ALPINE})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Not(Equal(0)))
+ Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"run", "--rm", "--restart", "always", ALPINE})
session.WaitWithDefaultTimeout()
diff --git a/test/python/docker/__init__.py b/test/python/docker/__init__.py
index 316b102f4..351834316 100644
--- a/test/python/docker/__init__.py
+++ b/test/python/docker/__init__.py
@@ -39,9 +39,7 @@ class Podman(object):
self.cmd.append("--root=" + os.path.join(self.anchor_directory, "crio"))
self.cmd.append("--runroot=" + os.path.join(self.anchor_directory, "crio-run"))
- os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(
- self.anchor_directory, "registry.conf"
- )
+ os.environ["REGISTRIES_CONFIG_PATH"] = os.path.join(self.anchor_directory, "registry.conf")
p = configparser.ConfigParser()
p.read_dict(
{
@@ -53,20 +51,16 @@ class Podman(object):
with open(os.environ["REGISTRIES_CONFIG_PATH"], "w") as w:
p.write(w)
- os.environ["CNI_CONFIG_PATH"] = os.path.join(
- self.anchor_directory, "cni", "net.d"
- )
+ os.environ["CNI_CONFIG_PATH"] = os.path.join(self.anchor_directory, "cni", "net.d")
os.makedirs(os.environ["CNI_CONFIG_PATH"], exist_ok=True)
self.cmd.append("--cni-config-dir=" + os.environ["CNI_CONFIG_PATH"])
- cni_cfg = os.path.join(
- os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist"
- )
+ cni_cfg = os.path.join(os.environ["CNI_CONFIG_PATH"], "87-podman-bridge.conflist")
# json decoded and encoded to ensure legal json
buf = json.loads(
"""
{
"cniVersion": "0.3.0",
- "name": "podman",
+ "name": "default",
"plugins": [{
"type": "bridge",
"bridge": "cni0",
diff --git a/test/python/docker/common.py b/test/python/docker/common.py
index e79d64a9b..11f512495 100644
--- a/test/python/docker/common.py
+++ b/test/python/docker/common.py
@@ -4,9 +4,7 @@ from test.python.docker import constant
def run_top_container(client: DockerClient):
- c = client.containers.create(
- constant.ALPINE, command="top", detach=True, tty=True, name="top"
- )
+ c = client.containers.create(constant.ALPINE, command="top", detach=True, tty=True, name="top")
c.start()
return c.id
diff --git a/test/python/docker/test_containers.py b/test/python/docker/test_containers.py
index 0fd419d9d..20d8417c3 100644
--- a/test/python/docker/test_containers.py
+++ b/test/python/docker/test_containers.py
@@ -87,7 +87,7 @@ class TestContainers(unittest.TestCase):
self.assertEqual(len(containers), 2)
def test_stop_container(self):
- top = self.client.containers.get("top")
+ top = self.client.containers.get(TestContainers.topContainerId)
self.assertEqual(top.status, "running")
# Stop a running container and validate the state
diff --git a/test/python/docker/test_images.py b/test/python/docker/test_images.py
index 7ef3d708b..1fa4aade9 100644
--- a/test/python/docker/test_images.py
+++ b/test/python/docker/test_images.py
@@ -78,9 +78,7 @@ class TestImages(unittest.TestCase):
self.assertEqual(len(self.client.images.list()), 2)
# List images with filter
- self.assertEqual(
- len(self.client.images.list(filters={"reference": "alpine"})), 1
- )
+ self.assertEqual(len(self.client.images.list(filters={"reference": "alpine"})), 1)
def test_search_image(self):
"""Search for image"""
diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go
index c6a9a660e..2769781f2 100644
--- a/vendor/github.com/containers/common/pkg/config/config.go
+++ b/vendor/github.com/containers/common/pkg/config/config.go
@@ -113,6 +113,10 @@ type ContainersConfig struct {
// DNSSearches set default DNS search domains.
DNSSearches []string `toml:"dns_searches,omitempty"`
+ // EnableKeyring tells the container engines whether to create
+ // a kernel keyring for use within the container
+ EnableKeyring bool `toml:"keyring,omitempty"`
+
// EnableLabeling tells the container engines whether to use MAC
// Labeling to separate containers (SELinux)
EnableLabeling bool `toml:"label,omitempty"`
diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf
index e8519b251..ed7c91931 100644
--- a/vendor/github.com/containers/common/pkg/config/containers.conf
+++ b/vendor/github.com/containers/common/pkg/config/containers.conf
@@ -146,9 +146,13 @@ default_sysctls = [
#
# ipcns = "private"
-# Flag tells container engine to whether to use container separation using
-# MAC(SELinux)labeling or not.
-# Flag is ignored on label disabled systems.
+# keyring tells the container engine whether to create
+# a kernel keyring for use within the container.
+# keyring = true
+
+# label tells the container engine whether to use container separation using
+# MAC(SELinux) labeling or not.
+# The label flag is ignored on label disabled systems.
#
# label = true
diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go
index 5f8f4999f..4f1460e3b 100644
--- a/vendor/github.com/containers/common/pkg/config/default.go
+++ b/vendor/github.com/containers/common/pkg/config/default.go
@@ -46,8 +46,6 @@ var (
DefaultInitPath = "/usr/libexec/podman/catatonit"
// DefaultInfraImage to use for infra container
DefaultInfraImage = "k8s.gcr.io/pause:3.2"
- // DefaultInfraCommand to be run in an infra container
- DefaultInfraCommand = "/pause"
// DefaultRootlessSHMLockPath is the default path for rootless SHM locks
DefaultRootlessSHMLockPath = "/libpod_rootless_lock"
// DefaultDetachKeys is the default keys sequence for detaching a
@@ -179,6 +177,7 @@ func DefaultConfig() (*Config, error) {
DNSServers: []string{},
DNSOptions: []string{},
DNSSearches: []string{},
+ EnableKeyring: true,
EnableLabeling: selinuxEnabled(),
Env: []string{
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
@@ -308,7 +307,6 @@ func defaultConfigFromMemory() (*EngineConfig, error) {
c.InitPath = DefaultInitPath
c.NoPivotRoot = false
- c.InfraCommand = DefaultInfraCommand
c.InfraImage = DefaultInfraImage
c.EnablePortReservation = true
c.NumLocks = 2048
diff --git a/vendor/github.com/containers/common/pkg/retry/retry.go b/vendor/github.com/containers/common/pkg/retry/retry.go
index d0ac19fb6..f6ecab0c0 100644
--- a/vendor/github.com/containers/common/pkg/retry/retry.go
+++ b/vendor/github.com/containers/common/pkg/retry/retry.go
@@ -30,7 +30,7 @@ func RetryIfNecessary(ctx context.Context, operation func() error, retryOptions
if retryOptions.Delay != 0 {
delay = retryOptions.Delay
}
- logrus.Infof("Warning: failed, retrying in %s ... (%d/%d)", delay, attempt+1, retryOptions.MaxRetry)
+ logrus.Infof("Warning: failed, retrying in %s ... (%d/%d). Error: %v", delay, attempt+1, retryOptions.MaxRetry, err)
select {
case <-time.After(delay):
break
diff --git a/vendor/github.com/containers/common/pkg/seccomp/default_linux.go b/vendor/github.com/containers/common/pkg/seccomp/default_linux.go
index ddc25ac67..09629724d 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/default_linux.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/default_linux.go
@@ -174,6 +174,7 @@ func DefaultProfile() *Seccomp {
"ioprio_get",
"ioprio_set",
"ipc",
+ "keyctl",
"kill",
"lchown",
"lchown32",
@@ -327,6 +328,7 @@ func DefaultProfile() *Seccomp {
"signalfd",
"signalfd4",
"sigreturn",
+ "socket",
"socketcall",
"socketpair",
"splice",
diff --git a/vendor/github.com/containers/common/pkg/seccomp/supported.go b/vendor/github.com/containers/common/pkg/seccomp/supported.go
index ab2a94a73..1177ef630 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/supported.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/supported.go
@@ -1,3 +1,5 @@
+// +build !windows
+
package seccomp
import (
diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go
index ef7c612e2..72f4e00f7 100644
--- a/vendor/github.com/containers/common/version/version.go
+++ b/vendor/github.com/containers/common/version/version.go
@@ -1,4 +1,4 @@
package version
// Version is the version of the build.
-const Version = "0.27.0"
+const Version = "0.29.0"
diff --git a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
index fadfe1a35..4001b65b6 100644
--- a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
+++ b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/shortnames.go
@@ -8,8 +8,8 @@ import (
"github.com/BurntSushi/toml"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
+ "github.com/containers/storage/pkg/homedir"
"github.com/containers/storage/pkg/lockfile"
- "github.com/docker/docker/pkg/homedir"
"github.com/pkg/errors"
)
diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go
index 3ef1c2410..14e553c9f 100644
--- a/vendor/github.com/containers/image/v5/version/version.go
+++ b/vendor/github.com/containers/image/v5/version/version.go
@@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 8
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 0
+ VersionPatch = 1
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = ""
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 53cc1a6f9..f9e8384bb 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.24.0
+1.24.1
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index 34c1ea7ad..86a5d8644 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -8,7 +8,7 @@ require (
github.com/Microsoft/hcsshim v0.8.9
github.com/docker/go-units v0.4.0
github.com/hashicorp/go-multierror v1.1.0
- github.com/klauspost/compress v1.11.2
+ github.com/klauspost/compress v1.11.3
github.com/klauspost/pgzip v1.2.5
github.com/mattn/go-shellwords v1.0.10
github.com/mistifyio/go-zfs v2.1.1+incompatible
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index bec6aa59a..a5d3f3b82 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -64,8 +64,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
-github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
+github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
diff --git a/vendor/github.com/containers/storage/pkg/unshare/unshare.go b/vendor/github.com/containers/storage/pkg/unshare/unshare.go
index a08fb674d..a9210b0bf 100644
--- a/vendor/github.com/containers/storage/pkg/unshare/unshare.go
+++ b/vendor/github.com/containers/storage/pkg/unshare/unshare.go
@@ -26,6 +26,7 @@ func HomeDir() (string, error) {
return
}
homeDir, homeDirErr = usr.HomeDir, nil
+ return
}
homeDir, homeDirErr = home, nil
})
diff --git a/vendor/github.com/klauspost/compress/flate/gen_inflate.go b/vendor/github.com/klauspost/compress/flate/gen_inflate.go
index b26d19ec2..35fc072a3 100644
--- a/vendor/github.com/klauspost/compress/flate/gen_inflate.go
+++ b/vendor/github.com/klauspost/compress/flate/gen_inflate.go
@@ -42,16 +42,6 @@ func (f *decompressor) $FUNCNAME$() {
stateDict
)
fr := f.r.($TYPE$)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
switch f.stepState {
case stateInit:
@@ -112,9 +102,7 @@ readLiteral:
}
}
- var n uint // number of bits extra
var length int
- var err error
switch {
case v < 256:
f.dict.writeByte(byte(v))
@@ -131,71 +119,97 @@ readLiteral:
// otherwise, reference to older data
case v < 265:
length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
for f.nb < n {
- if err = moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits n>0:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
f.b >>= n & regSizeMaskUint32
f.nb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
}
var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- sym, err := f.huffSym(f.hd)
- if err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ nb, b := f.nb, f.b
+ for {
+ for nb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b = b
+ f.nb = nb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ b |= uint32(c) << (nb & regSizeMaskUint32)
+ nb += 8
+ }
+ chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= nb {
+ if n == 0 {
+ f.b = b
+ f.nb = nb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ f.b = b >> (n & regSizeMaskUint32)
+ f.nb = nb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
}
- f.err = err
- return
}
- dist = uint32(sym)
}
switch {
@@ -206,13 +220,17 @@ readLiteral:
// have 1 bit in bottom of dist, need nb more.
extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
f.b >>= nb & regSizeMaskUint32
diff --git a/vendor/github.com/klauspost/compress/flate/inflate.go b/vendor/github.com/klauspost/compress/flate/inflate.go
index 189e9fe0b..16bc51408 100644
--- a/vendor/github.com/klauspost/compress/flate/inflate.go
+++ b/vendor/github.com/klauspost/compress/flate/inflate.go
@@ -29,6 +29,13 @@ const (
debugDecode = false
)
+// Value of length - 3 and extra bits.
+type lengthExtra struct {
+ length, extra uint8
+}
+
+var decCodeToLen = [32]lengthExtra{{length: 0x0, extra: 0x0}, {length: 0x1, extra: 0x0}, {length: 0x2, extra: 0x0}, {length: 0x3, extra: 0x0}, {length: 0x4, extra: 0x0}, {length: 0x5, extra: 0x0}, {length: 0x6, extra: 0x0}, {length: 0x7, extra: 0x0}, {length: 0x8, extra: 0x1}, {length: 0xa, extra: 0x1}, {length: 0xc, extra: 0x1}, {length: 0xe, extra: 0x1}, {length: 0x10, extra: 0x2}, {length: 0x14, extra: 0x2}, {length: 0x18, extra: 0x2}, {length: 0x1c, extra: 0x2}, {length: 0x20, extra: 0x3}, {length: 0x28, extra: 0x3}, {length: 0x30, extra: 0x3}, {length: 0x38, extra: 0x3}, {length: 0x40, extra: 0x4}, {length: 0x50, extra: 0x4}, {length: 0x60, extra: 0x4}, {length: 0x70, extra: 0x4}, {length: 0x80, extra: 0x5}, {length: 0xa0, extra: 0x5}, {length: 0xc0, extra: 0x5}, {length: 0xe0, extra: 0x5}, {length: 0xff, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}, {length: 0x0, extra: 0x0}}
+
// Initialize the fixedHuffmanDecoder only once upon first use.
var fixedOnce sync.Once
var fixedHuffmanDecoder huffmanDecoder
diff --git a/vendor/github.com/klauspost/compress/flate/inflate_gen.go b/vendor/github.com/klauspost/compress/flate/inflate_gen.go
index 9a92a1b30..cc6db2792 100644
--- a/vendor/github.com/klauspost/compress/flate/inflate_gen.go
+++ b/vendor/github.com/klauspost/compress/flate/inflate_gen.go
@@ -20,16 +20,6 @@ func (f *decompressor) huffmanBytesBuffer() {
stateDict
)
fr := f.r.(*bytes.Buffer)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
switch f.stepState {
case stateInit:
@@ -90,9 +80,7 @@ readLiteral:
}
}
- var n uint // number of bits extra
var length int
- var err error
switch {
case v < 256:
f.dict.writeByte(byte(v))
@@ -109,71 +97,97 @@ readLiteral:
// otherwise, reference to older data
case v < 265:
length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
for f.nb < n {
- if err = moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits n>0:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
f.b >>= n & regSizeMaskUint32
f.nb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
}
var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- sym, err := f.huffSym(f.hd)
- if err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ nb, b := f.nb, f.b
+ for {
+ for nb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b = b
+ f.nb = nb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ b |= uint32(c) << (nb & regSizeMaskUint32)
+ nb += 8
+ }
+ chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= nb {
+ if n == 0 {
+ f.b = b
+ f.nb = nb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ f.b = b >> (n & regSizeMaskUint32)
+ f.nb = nb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
}
- f.err = err
- return
}
- dist = uint32(sym)
}
switch {
@@ -184,13 +198,17 @@ readLiteral:
// have 1 bit in bottom of dist, need nb more.
extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
f.b >>= nb & regSizeMaskUint32
@@ -246,16 +264,6 @@ func (f *decompressor) huffmanBytesReader() {
stateDict
)
fr := f.r.(*bytes.Reader)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
switch f.stepState {
case stateInit:
@@ -316,9 +324,7 @@ readLiteral:
}
}
- var n uint // number of bits extra
var length int
- var err error
switch {
case v < 256:
f.dict.writeByte(byte(v))
@@ -335,71 +341,97 @@ readLiteral:
// otherwise, reference to older data
case v < 265:
length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
for f.nb < n {
- if err = moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits n>0:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
f.b >>= n & regSizeMaskUint32
f.nb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
}
var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- sym, err := f.huffSym(f.hd)
- if err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ nb, b := f.nb, f.b
+ for {
+ for nb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b = b
+ f.nb = nb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ b |= uint32(c) << (nb & regSizeMaskUint32)
+ nb += 8
+ }
+ chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= nb {
+ if n == 0 {
+ f.b = b
+ f.nb = nb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ f.b = b >> (n & regSizeMaskUint32)
+ f.nb = nb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
}
- f.err = err
- return
}
- dist = uint32(sym)
}
switch {
@@ -410,13 +442,17 @@ readLiteral:
// have 1 bit in bottom of dist, need nb more.
extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
f.b >>= nb & regSizeMaskUint32
@@ -472,16 +508,6 @@ func (f *decompressor) huffmanBufioReader() {
stateDict
)
fr := f.r.(*bufio.Reader)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
switch f.stepState {
case stateInit:
@@ -542,9 +568,7 @@ readLiteral:
}
}
- var n uint // number of bits extra
var length int
- var err error
switch {
case v < 256:
f.dict.writeByte(byte(v))
@@ -561,71 +585,97 @@ readLiteral:
// otherwise, reference to older data
case v < 265:
length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
for f.nb < n {
- if err = moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits n>0:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
f.b >>= n & regSizeMaskUint32
f.nb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
}
var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- sym, err := f.huffSym(f.hd)
- if err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ nb, b := f.nb, f.b
+ for {
+ for nb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b = b
+ f.nb = nb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ b |= uint32(c) << (nb & regSizeMaskUint32)
+ nb += 8
+ }
+ chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= nb {
+ if n == 0 {
+ f.b = b
+ f.nb = nb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ f.b = b >> (n & regSizeMaskUint32)
+ f.nb = nb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
}
- f.err = err
- return
}
- dist = uint32(sym)
}
switch {
@@ -636,13 +686,17 @@ readLiteral:
// have 1 bit in bottom of dist, need nb more.
extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
f.b >>= nb & regSizeMaskUint32
@@ -698,16 +752,6 @@ func (f *decompressor) huffmanStringsReader() {
stateDict
)
fr := f.r.(*strings.Reader)
- moreBits := func() error {
- c, err := fr.ReadByte()
- if err != nil {
- return noEOF(err)
- }
- f.roffset++
- f.b |= uint32(c) << f.nb
- f.nb += 8
- return nil
- }
switch f.stepState {
case stateInit:
@@ -768,9 +812,7 @@ readLiteral:
}
}
- var n uint // number of bits extra
var length int
- var err error
switch {
case v < 256:
f.dict.writeByte(byte(v))
@@ -787,71 +829,97 @@ readLiteral:
// otherwise, reference to older data
case v < 265:
length = v - (257 - 3)
- n = 0
- case v < 269:
- length = v*2 - (265*2 - 11)
- n = 1
- case v < 273:
- length = v*4 - (269*4 - 19)
- n = 2
- case v < 277:
- length = v*8 - (273*8 - 35)
- n = 3
- case v < 281:
- length = v*16 - (277*16 - 67)
- n = 4
- case v < 285:
- length = v*32 - (281*32 - 131)
- n = 5
case v < maxNumLit:
- length = 258
- n = 0
- default:
- if debugDecode {
- fmt.Println(v, ">= maxNumLit")
- }
- f.err = CorruptInputError(f.roffset)
- return
- }
- if n > 0 {
+ val := decCodeToLen[(v - 257)]
+ length = int(val.length) + 3
+ n := uint(val.extra)
for f.nb < n {
- if err = moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits n>0:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
f.b >>= n & regSizeMaskUint32
f.nb -= n
+ default:
+ if debugDecode {
+ fmt.Println(v, ">= maxNumLit")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
}
var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- sym, err := f.huffSym(f.hd)
- if err != nil {
- if debugDecode {
- fmt.Println("huffsym:", err)
+ // Since a huffmanDecoder can be empty or be composed of a degenerate tree
+ // with single element, huffSym must error on these two edge cases. In both
+ // cases, the chunks slice will be 0 for the invalid sequence, leading it
+ // satisfy the n == 0 check below.
+ n := uint(f.hd.maxRead)
+ // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers,
+ // but is smart enough to keep local variables in registers, so use nb and b,
+ // inline call to moreBits and reassign b,nb back to f on return.
+ nb, b := f.nb, f.b
+ for {
+ for nb < n {
+ c, err := fr.ReadByte()
+ if err != nil {
+ f.b = b
+ f.nb = nb
+ f.err = noEOF(err)
+ return
+ }
+ f.roffset++
+ b |= uint32(c) << (nb & regSizeMaskUint32)
+ nb += 8
+ }
+ chunk := f.hd.chunks[b&(huffmanNumChunks-1)]
+ n = uint(chunk & huffmanCountMask)
+ if n > huffmanChunkBits {
+ chunk = f.hd.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hd.linkMask]
+ n = uint(chunk & huffmanCountMask)
+ }
+ if n <= nb {
+ if n == 0 {
+ f.b = b
+ f.nb = nb
+ if debugDecode {
+ fmt.Println("huffsym: n==0")
+ }
+ f.err = CorruptInputError(f.roffset)
+ return
+ }
+ f.b = b >> (n & regSizeMaskUint32)
+ f.nb = nb - n
+ dist = uint32(chunk >> huffmanValueShift)
+ break
}
- f.err = err
- return
}
- dist = uint32(sym)
}
switch {
@@ -862,13 +930,17 @@ readLiteral:
// have 1 bit in bottom of dist, need nb more.
extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = f.moreBits(); err != nil {
+ c, err := fr.ReadByte()
+ if err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
f.err = err
return
}
+ f.roffset++
+ f.b |= uint32(c) << f.nb
+ f.nb += 8
}
extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
f.b >>= nb & regSizeMaskUint32
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index 07f7285f0..08e553f75 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -54,11 +54,11 @@ To create a writer with default options, do like this:
```Go
// Compress input to output.
func Compress(in io.Reader, out io.Writer) error {
- w, err := NewWriter(output)
+ enc, err := zstd.NewWriter(out)
if err != nil {
return err
}
- _, err := io.Copy(w, input)
+ _, err = io.Copy(enc, in)
if err != nil {
enc.Close()
return err
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
index d78be6d42..cdda0de58 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -323,19 +323,23 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
}
if frame.FrameContentSize > 0 && frame.FrameContentSize < 1<<30 {
// Never preallocate moe than 1 GB up front.
- if uint64(cap(dst)) < frame.FrameContentSize {
+ if cap(dst)-len(dst) < int(frame.FrameContentSize) {
dst2 := make([]byte, len(dst), len(dst)+int(frame.FrameContentSize))
copy(dst2, dst)
dst = dst2
}
}
if cap(dst) == 0 {
- // Allocate window size * 2 by default if nothing is provided and we didn't get frame content size.
- size := frame.WindowSize * 2
+ // Allocate len(input) * 2 by default if nothing is provided
+ // and we didn't get frame content size.
+ size := len(input) * 2
// Cap to 1 MB.
if size > 1<<20 {
size = 1 << 20
}
+ if uint64(size) > d.o.maxDecodedSize {
+ size = int(d.o.maxDecodedSize)
+ }
dst = make([]byte, 0, size)
}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 320d9851f..674b7a4e4 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -88,7 +88,7 @@ github.com/containers/buildah/pkg/secrets
github.com/containers/buildah/pkg/supplemented
github.com/containers/buildah/pkg/umask
github.com/containers/buildah/util
-# github.com/containers/common v0.27.0
+# github.com/containers/common v0.29.0
github.com/containers/common/pkg/apparmor
github.com/containers/common/pkg/apparmor/internal/supported
github.com/containers/common/pkg/auth
@@ -104,7 +104,7 @@ github.com/containers/common/pkg/sysinfo
github.com/containers/common/version
# github.com/containers/conmon v2.0.20+incompatible
github.com/containers/conmon/runner/config
-# github.com/containers/image/v5 v5.8.0
+# github.com/containers/image/v5 v5.8.1
github.com/containers/image/v5/copy
github.com/containers/image/v5/directory
github.com/containers/image/v5/directory/explicitfilepath
@@ -168,7 +168,7 @@ github.com/containers/psgo/internal/dev
github.com/containers/psgo/internal/host
github.com/containers/psgo/internal/proc
github.com/containers/psgo/internal/process
-# github.com/containers/storage v1.24.0
+# github.com/containers/storage v1.24.1
github.com/containers/storage
github.com/containers/storage/drivers
github.com/containers/storage/drivers/aufs
@@ -339,7 +339,7 @@ github.com/json-iterator/go
# github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a
github.com/juju/ansiterm
github.com/juju/ansiterm/tabwriter
-# github.com/klauspost/compress v1.11.2
+# github.com/klauspost/compress v1.11.3
github.com/klauspost/compress/flate
github.com/klauspost/compress/fse
github.com/klauspost/compress/huff0