summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/actions/check_cirrus_cron/cron_failures.sh116
-rw-r--r--.github/workflows/check_cirrus_cron.yml81
-rw-r--r--cmd/podman/common/completion.go442
-rw-r--r--cmd/podman/common/create.go18
-rw-r--r--cmd/podman/common/create_opts.go73
-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.go23
-rw-r--r--cmd/podman/containers/top.go8
-rw-r--r--cmd/podman/images/list.go3
-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/ps.go3
-rw-r--r--cmd/podman/root.go52
-rw-r--r--cmd/podman/volumes/list.go2
-rw-r--r--contrib/cirrus/cron-fail_addrs.csv1
-rw-r--r--contrib/systemd/system/podman.service3
-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-ps.1.md8
-rw-r--r--docs/source/markdown/podman-run.1.md9
-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.md8
-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/network/subnet.go14
-rw-r--r--libpod/network/subnet_test.go62
-rw-r--r--libpod/networking_linux.go21
-rw-r--r--libpod/rootless_cni_linux.go4
-rw-r--r--pkg/api/handlers/compat/containers.go15
-rw-r--r--pkg/api/handlers/compat/info.go3
-rw-r--r--pkg/api/handlers/libpod/containers.go24
-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/e2e/config/containers-remote.conf51
-rw-r--r--test/e2e/containers_conf_test.go68
-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--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
82 files changed, 1736 insertions, 792 deletions
diff --git a/.github/actions/check_cirrus_cron/cron_failures.sh b/.github/actions/check_cirrus_cron/cron_failures.sh
new file mode 100755
index 000000000..2693df417
--- /dev/null
+++ b/.github/actions/check_cirrus_cron/cron_failures.sh
@@ -0,0 +1,116 @@
+#!/bin/bash
+
+set -eo pipefail
+
+# Intended to be executed from a github action workflow step.
+# Outputs the Cirrus cron names and IDs of any failed builds
+
+err() {
+ # Ref: https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions
+ echo "::error file=${BASH_SOURCE[0]},line=${BASH_LINENO[0]}::${1:-No error message given}"
+ exit 1
+}
+
+_errfmt="Expecting %s value to not be empty"
+if [[ -z "$GITHUB_REPOSITORY" ]]; then
+ err $(printf "$_errfmt" "\$GITHUB_REPOSITORY")
+elif [[ -z "$NAME_ID_FILEPATH" ]]; then
+ err $(printf "$_errfmt" "\$NAME_ID_FILEPATH")
+fi
+
+mkdir -p artifacts
+cat > ./artifacts/query_raw.json << "EOF"
+{"query":"
+ query CronNameStatus($owner: String!, $repo: String!) {
+ githubRepository(owner: $owner, name: $repo) {
+ cronSettings {
+ name
+ lastInvocationBuild {
+ id
+ status
+ }
+ }
+ }
+ }
+",
+"variables":"{
+ \"owner\": \"@@OWNER@@\",
+ \"repo\": \"@@REPO@@\"
+}"}
+EOF
+# Makes for easier copy/pasting query to/from
+# https://cirrus-ci.com/explorer
+owner=$(cut -d '/' -f 1 <<<"$GITHUB_REPOSITORY")
+repo=$(cut -d '/' -f 2 <<<"$GITHUB_REPOSITORY")
+sed -i -r -e "s/@@OWNER@@/$owner/g" -e "s/@@REPO@@/$repo/g" ./artifacts/query_raw.json
+
+echo "::group::Posting GraphQL Query"
+# Easier to debug in error-reply when query is compacted
+tr -d '\n' < ./artifacts/query_raw.json | tr -s ' ' | tee ./artifacts/query.json | \
+ jq --indent 4 --color-output .
+
+if grep -q '@@' ./artifacts/query.json; then
+ err "Found unreplaced substitution token in raw query JSON"
+fi
+curl \
+ --request POST \
+ --silent \
+ --location \
+ --header 'content-type: application/json' \
+ --url 'https://api.cirrus-ci.com/graphql' \
+ --data @./artifacts/query.json \
+ --output ./artifacts/reply.json
+echo "::endgroup::"
+
+echo "::group::Received GraphQL Reply"
+jq --indent 4 --color-output . <./artifacts/reply.json || \
+ cat ./artifacts/reply.json
+echo "::endgroup::"
+
+# Desireable to catch non-JSON encoded errors in reply.
+if grep -qi 'error' ./artifacts/reply.json; then
+ err "Found the word 'error' in reply"
+fi
+
+# e.x. reply.json
+# {
+# "data": {
+# "githubRepository": {
+# "cronSettings": [
+# {
+# "name": "Keepalive_v2.0",
+# "lastInvocationBuild": {
+# "id": "5776050544181248",
+# "status": "EXECUTING"
+# }
+# },
+# {
+# "name": "Keepalive_v1.9",
+# "lastInvocationBuild": {
+# "id": "5962921081569280",
+# "status": "COMPLETED"
+# }
+# },
+# {
+# "name": "Keepalive_v2.0.5-rhel",
+# "lastInvocationBuild": {
+# "id": "5003065549914112",
+# "status": "FAILED"
+# }
+# }
+# ]
+# }
+# }
+# }
+_filt='.data.githubRepository.cronSettings | map(select(.lastInvocationBuild.status=="FAILED") | { name:.name, id:.lastInvocationBuild.id} | join(" ")) | join("\n")'
+jq --raw-output "$_filt" ./artifacts/reply.json > "$NAME_ID_FILEPATH"
+
+echo "<Cron Name> <Failed Build ID>"
+cat "$NAME_ID_FILEPATH"
+
+# Don't rely on a newline present for zero/one output line, always count words
+records=$(wc --words "$NAME_ID_FILEPATH" | cut -d ' ' -f 1)
+# Always two words per record
+failures=$((records/2))
+echo "::set-output name=failures::$failures"
+echo "Total failed Cirrus-CI cron builds: $failures"
diff --git a/.github/workflows/check_cirrus_cron.yml b/.github/workflows/check_cirrus_cron.yml
new file mode 100644
index 000000000..86f8c26dc
--- /dev/null
+++ b/.github/workflows/check_cirrus_cron.yml
@@ -0,0 +1,81 @@
+---
+
+# Format Ref: https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions
+
+# Required to un-FUBAR default ${{github.workflow}} value
+name: check_cirrus_cron
+
+on:
+ schedule:
+ # Assume cirrus cron jobs runs at least once per day
+ - cron: '59 23 * * *'
+ # Debug: Allow triggering job manually in github-actions WebUI
+ workflow_dispatch: {}
+
+env:
+ # Debug-mode can reveal secrets, only enable by a secret value.
+ # Ref: https://help.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#enabling-step-debug-logging
+ ACTIONS_STEP_DEBUG: '${{ secrets.ACTIONS_STEP_DEBUG }}'
+ # File with CSV listing of zero or more e-mail addresses for delivery
+ # of daily failure notice e-mails.
+ FAILMAILCSV: './contrib/cirrus/cron-fail_addrs.csv'
+ # Filename for table of cron-name to build-id data
+ # (must be in $GITHUB_WORKSPACE/artifacts/)
+ NAME_ID_FILEPATH: './artifacts/name_id.txt'
+
+jobs:
+ cron_failures:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ ref: master
+ persist-credentials: false
+
+ - name: Get failed cron names and Build IDs
+ id: cron
+ run: './.github/actions/${{ github.workflow }}/${{ github.job }}.sh'
+
+ - if: steps.cron.outputs.failures > 0
+ shell: bash
+ # Must be inline, since context expressions are used.
+ # Ref: https://docs.github.com/en/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions
+ run: |
+ set -eo pipefail
+ (
+ echo "Detected one or more Cirrus-CI cron-triggered jobs have failed recently:"
+ echo ""
+
+ while read -r NAME BID; do
+ echo "Cron build '$NAME' Failed: https://cirrus-ci.com/build/$BID"
+ done < "$NAME_ID_FILEPATH"
+
+ echo ""
+ echo "# Source: ${{ github.workflow }} workflow on ${{ github.repository }}."
+ # Separate content from sendgrid.com automatic footer.
+ echo ""
+ ) > ./artifacts/email_body.txt
+
+ - if: steps.cron.outputs.failures > 0
+ id: mailto
+ run: printf "::set-output name=csv::%s\n" $(cat "$FAILMAILCSV")
+
+ - if: steps.mailto.outputs.csv != ''
+ name: Send failure notification e-mail
+ # Ref: https://github.com/dawidd6/action-send-mail
+ uses: dawidd6/action-send-mail@v2.2.2
+ with:
+ server_address: ${{secrets.ACTION_MAIL_SERVER}}
+ server_port: 465
+ username: ${{secrets.ACTION_MAIL_USERNAME}}
+ password: ${{secrets.ACTION_MAIL_PASSWORD}}
+ subject: Cirrus-CI cron build failures on ${{github.repository}}
+ to: ${{steps.mailto.outputs.csv}}
+ from: ${{secrets.ACTION_MAIL_SENDER}}
+ body: file://./artifacts/email_body.txt
+
+ - if: always()
+ uses: actions/upload-artifact@v2
+ with:
+ name: ${{ github.job }}_artifacts
+ path: artifacts/*
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 00123f9e6..6723cbf62 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/registries"
+ "github.com/containers/podman/v2/pkg/rootless"
systemdGen "github.com/containers/podman/v2/pkg/systemd/generate"
"github.com/spf13/cobra"
)
@@ -23,104 +24,132 @@ var (
LogLevels = []string{"debug", "info", "warn", "error", "fatal", "panic"}
)
-func getContainers(toComplete string, statuses ...string) ([]string, cobra.ShellCompDirective) {
+type completeType int
+
+const (
+ // complete names and IDs after two chars
+ completeDefault completeType = iota
+ // only complete IDs
+ completeIDs
+ // only complete Names
+ completeNames
+)
+
+type keyValueCompletion map[string]func(s 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),
}
listOpts.All = true
listOpts.Pod = true
+ if len(statuses) > 0 {
+ listOpts.Filters["status"] = statuses
+ }
- // TODO: The api doesn't handle several different statuses correct see:
- // https://github.com/containers/podman/issues/8344
- // Instead of looping over the statuses we should be able to set
- // listOpts.Filters["status"] = statuses
-
- var containers []entities.ListContainer
- var err error
- if len(statuses) == 0 {
- containers, err = registry.ContainerEngine().ContainerList(registry.GetContext(), listOpts)
- if err != nil {
- cobra.CompErrorln(err.Error())
- return nil, cobra.ShellCompDirectiveError
- }
- } else {
- for _, s := range statuses {
- listOpts.Filters["status"] = []string{s}
- res, err := registry.ContainerEngine().ContainerList(registry.GetContext(), listOpts)
- if err != nil {
- cobra.CompErrorln(err.Error())
- return nil, cobra.ShellCompDirectiveError
- }
- containers = append(containers, res...)
- }
+ 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.ShellCompDirectiveNoFileComp
}
for _, c := range containers {
- // include ids in suggestions if more then 2 chars are typed
- if len(toComplete) > 1 && strings.HasPrefix(c.ID, toComplete) {
+ // include ids in suggestions if cType == completeIDs or
+ // more then 2 chars are typed and cType == completeDefault
+ if ((len(toComplete) > 1 && cType == completeDefault) ||
+ cType == completeIDs) && strings.HasPrefix(c.ID, toComplete) {
suggestions = append(suggestions, c.ID[0:12]+"\t"+c.PodName)
}
// include name in suggestions
- if strings.HasPrefix(c.Names[0], toComplete) {
+ if cType != completeIDs && strings.HasPrefix(c.Names[0], toComplete) {
suggestions = append(suggestions, c.Names[0]+"\t"+c.PodName)
}
}
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
-func getPods(toComplete string, 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),
}
+ if len(statuses) > 0 {
+ listOpts.Filters["status"] = statuses
+ }
- // TODO: The api doesn't handle several different statuses correct see:
- // https://github.com/containers/podman/issues/8344
- // Instead of looping over the statuses we should be able to set
- // listOpts.Filters["status"] = statuses
-
- var pods []*entities.ListPodsReport
- var err error
- if len(statuses) == 0 {
- pods, err = registry.ContainerEngine().PodPs(registry.GetContext(), listOpts)
- if err != nil {
- cobra.CompErrorln(err.Error())
- return nil, cobra.ShellCompDirectiveError
- }
- } else {
- for _, s := range statuses {
- listOpts.Filters["status"] = []string{s}
- res, err := registry.ContainerEngine().PodPs(registry.GetContext(), listOpts)
- if err != nil {
- cobra.CompErrorln(err.Error())
- return nil, cobra.ShellCompDirectiveError
- }
- pods = append(pods, res...)
- }
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ pods, err := engine.PodPs(registry.GetContext(), listOpts)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for _, pod := range pods {
- // include ids in suggestions if more then 2 chars are typed
- if len(toComplete) > 1 && strings.HasPrefix(pod.Id, toComplete) {
+ // include ids in suggestions if cType == completeIDs or
+ // more then 2 chars are typed and cType == completeDefault
+ if ((len(toComplete) > 1 && cType == completeDefault) ||
+ cType == completeIDs) && strings.HasPrefix(pod.Id, toComplete) {
suggestions = append(suggestions, pod.Id[0:12])
}
// include name in suggestions
- if strings.HasPrefix(pod.Name, toComplete) {
+ if cType != completeIDs && strings.HasPrefix(pod.Name, toComplete) {
suggestions = append(suggestions, pod.Name)
}
}
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 {
@@ -131,14 +160,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.ShellCompDirectiveError
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ images, err := engine.List(registry.GetContext(), listOptions)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
for _, image := range images {
@@ -181,25 +215,30 @@ 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{
- Filter: "name=" + toComplete,
- }
+ 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.ShellCompDirectiveError
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ networks, err := engine.NetworkList(registry.Context(), networkListOptions)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveNoFileComp
}
- for _, network := range networks {
- suggestions = append(suggestions, network.Name)
+ for _, n := range networks {
+ if strings.HasPrefix(n.Name, toComplete) {
+ suggestions = append(suggestions, n.Name)
+ }
}
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
@@ -244,6 +283,36 @@ func validCurrentCmdLine(cmd *cobra.Command, args []string, toComplete string) b
return true
}
+func prefixSlice(pre string, slice []string) []string {
+ for i := range slice {
+ slice[i] = pre + slice[i]
+ }
+ return slice
+}
+
+func completeKeyValues(toComplete string, k keyValueCompletion) ([]string, cobra.ShellCompDirective) {
+ suggestions := make([]string, 0, len(k))
+ directive := cobra.ShellCompDirectiveNoFileComp
+ for key, getComps := range k {
+ if strings.HasPrefix(toComplete, key) {
+ if getComps != nil {
+ suggestions, dir := getComps(toComplete[len(key):])
+ return prefixSlice(key, suggestions), dir
+ }
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ if strings.HasPrefix(key, toComplete) {
+ suggestions = append(suggestions, key)
+ latKey := key[len(key)-1:]
+ if latKey == "=" || latKey == ":" {
+ // make sure we don't add a space after ':' or '='
+ directive = cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
+ }
+ }
+ }
+ return suggestions, directive
+}
+
/* Autocomplete Functions for cobra ValidArgsFunction */
// AutocompleteContainers - Autocomplete all container names.
@@ -251,7 +320,7 @@ func AutocompleteContainers(cmd *cobra.Command, args []string, toComplete string
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete)
+ return getContainers(cmd, toComplete, completeDefault)
}
// AutocompleteContainersCreated - Autocomplete only created container names.
@@ -259,7 +328,7 @@ func AutocompleteContainersCreated(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, "created")
+ return getContainers(cmd, toComplete, completeDefault, "created")
}
// AutocompleteContainersExited - Autocomplete only exited container names.
@@ -267,7 +336,7 @@ func AutocompleteContainersExited(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, "exited")
+ return getContainers(cmd, toComplete, completeDefault, "exited")
}
// AutocompleteContainersPaused - Autocomplete only paused container names.
@@ -275,7 +344,7 @@ func AutocompleteContainersPaused(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, "paused")
+ return getContainers(cmd, toComplete, completeDefault, "paused")
}
// AutocompleteContainersRunning - Autocomplete only running container names.
@@ -283,7 +352,7 @@ func AutocompleteContainersRunning(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, "running")
+ return getContainers(cmd, toComplete, completeDefault, "running")
}
// AutocompleteContainersStartable - Autocomplete only created and exited container names.
@@ -291,7 +360,7 @@ func AutocompleteContainersStartable(cmd *cobra.Command, args []string, toComple
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getContainers(toComplete, "created", "exited")
+ return getContainers(cmd, toComplete, completeDefault, "created", "exited")
}
// AutocompletePods - Autocomplete all pod names.
@@ -299,7 +368,7 @@ func AutocompletePods(cmd *cobra.Command, args []string, toComplete string) ([]s
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getPods(toComplete)
+ return getPods(cmd, toComplete, completeDefault)
}
// AutocompletePodsRunning - Autocomplete only running pod names.
@@ -308,7 +377,7 @@ func AutocompletePodsRunning(cmd *cobra.Command, args []string, toComplete strin
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getPods(toComplete, "running", "degraded")
+ return getPods(cmd, toComplete, completeDefault, "running", "degraded")
}
// AutocompleteContainersAndPods - Autocomplete container names and pod names.
@@ -316,8 +385,8 @@ func AutocompleteContainersAndPods(cmd *cobra.Command, args []string, toComplete
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- containers, _ := getContainers(toComplete)
- pods, _ := getPods(toComplete)
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
+ pods, _ := getPods(cmd, toComplete, completeDefault)
return append(containers, pods...), cobra.ShellCompDirectiveNoFileComp
}
@@ -326,8 +395,8 @@ func AutocompleteContainersAndImages(cmd *cobra.Command, args []string, toComple
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- containers, _ := getContainers(toComplete)
- images, _ := getImages(toComplete)
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
+ images, _ := getImages(cmd, toComplete)
return append(containers, images...), cobra.ShellCompDirectiveNoFileComp
}
@@ -336,7 +405,7 @@ func AutocompleteVolumes(cmd *cobra.Command, args []string, toComplete string) (
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getVolumes(toComplete)
+ return getVolumes(cmd, toComplete)
}
// AutocompleteImages - Autocomplete images.
@@ -344,7 +413,7 @@ func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getImages(toComplete)
+ return getImages(cmd, toComplete)
}
// AutocompleteCreateRun - Autocomplete only the fist argument as image and then do file completion.
@@ -353,7 +422,7 @@ func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string)
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) < 1 {
- return getImages(toComplete)
+ return getImages(cmd, toComplete)
}
// TODO: add path completion for files in the image
return nil, cobra.ShellCompDirectiveDefault
@@ -372,7 +441,7 @@ func AutocompleteNetworks(cmd *cobra.Command, args []string, toComplete string)
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
- return getNetworks(toComplete)
+ return getNetworks(cmd, toComplete)
}
// AutocompleteCpCommand - Autocomplete podman cp command args.
@@ -381,7 +450,7 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) < 2 {
- containers, _ := getContainers(toComplete)
+ containers, _ := getContainers(cmd, toComplete, completeDefault)
for _, container := range containers {
// TODO: Add path completion for inside the container if possible
if strings.HasPrefix(container, toComplete) {
@@ -395,6 +464,18 @@ 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
+}
+
// AutocompleteSystemConnections - Autocomplete system connections.
func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if !validCurrentCmdLine(cmd, args, toComplete) {
@@ -404,7 +485,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 {
@@ -448,40 +529,20 @@ func AutocompleteCreateAttach(cmd *cobra.Command, args []string, toComplete stri
// AutocompleteNamespace - Autocomplete namespace options.
// -> host,container:[name],ns:[path],private
func AutocompleteNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- namespacesOptions := []string{"host", "container:", "ns:", "private"}
-
- switch {
- case strings.HasPrefix(toComplete, "container:"):
- // Complete containers after colon
- containers, _ := getContainers(toComplete[10:]) //trim "container:"
-
- // add "container:" in front of the suggestions
- var suggestions []string
- for _, container := range containers {
- suggestions = append(suggestions, "container:"+container)
- }
-
- return suggestions, cobra.ShellCompDirectiveNoFileComp
-
- case strings.HasPrefix(toComplete, "ns:"):
- // Complete path after colon
- return nil, cobra.ShellCompDirectiveDefault
-
- case strings.HasPrefix(toComplete, "c") || strings.HasPrefix(toComplete, "n"):
- // don't insert space for container: and ns:
- return []string{"container:", "ns:"}, cobra.ShellCompDirectiveNoSpace
+ kv := keyValueCompletion{
+ "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,
}
- return namespacesOptions, cobra.ShellCompDirectiveNoFileComp
+ return completeKeyValues(toComplete, kv)
}
// AutocompleteUserNamespace - Autocomplete namespace options.
// -> same as AutocompleteNamespace with "auto", "keep-id" added
func AutocompleteUserNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
results, directive := AutocompleteNamespace(cmd, args, toComplete)
- if directive == cobra.ShellCompDirectiveNoFileComp {
- // add the auto and keep-id options
- results = append(results, "auto", "keep-id")
- }
+ results = append(results, "auto", "keep-id")
return results, directive
}
@@ -535,29 +596,18 @@ func AutocompleteRestartOption(cmd *cobra.Command, args []string, toComplete str
// AutocompleteSecurityOption - Autocomplete security options options.
func AutocompleteSecurityOption(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- SecurityOptions := []string{"apparmor=", "no-new-privileges", "seccomp=", "label="}
- switch {
- case strings.HasPrefix(toComplete, "apparmor=u"):
- // add space after unconfined
- return []string{"apparmor=unconfined"}, cobra.ShellCompDirectiveNoFileComp
-
- case strings.HasPrefix(toComplete, "label=d"):
- // add space after disable
- return []string{"label=disable"}, cobra.ShellCompDirectiveNoFileComp
-
- case strings.HasPrefix(toComplete, "label="):
- return []string{"label=user:", "label=role:", "label=type:", "label=level:", "label=filetype:", "label=disable"},
- cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
-
- case strings.HasPrefix(toComplete, "seccomp="):
- // complete files
- return nil, cobra.ShellCompDirectiveDefault
-
- case strings.HasPrefix(toComplete, "n"):
- // add space if no-new-privileges
- return []string{"no-new-privileges"}, cobra.ShellCompDirectiveNoFileComp
+ kv := keyValueCompletion{
+ "apparmor=": nil,
+ "no-new-privileges": nil,
+ "seccomp=": func(s string) ([]string, cobra.ShellCompDirective) { return nil, cobra.ShellCompDirectiveDefault },
+ "label=": func(s string) ([]string, cobra.ShellCompDirective) {
+ if strings.HasPrefix(s, "d") {
+ return []string{"disable"}, cobra.ShellCompDirectiveNoFileComp
+ }
+ return []string{"user:", "role:", "type:", "level:", "filetype:", "disable"}, cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
+ },
}
- return SecurityOptions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
+ return completeKeyValues(toComplete, kv)
}
// AutocompleteStopSignal - Autocomplete stop signal options.
@@ -583,7 +633,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()
@@ -599,7 +650,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
}
@@ -608,7 +660,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()
@@ -623,7 +676,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
}
@@ -639,7 +692,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
@@ -657,8 +710,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.
@@ -763,3 +830,92 @@ func AutocompleteSDNotify(cmd *cobra.Command, args []string, toComplete string)
types := []string{"container", "conmon", "ignore"}
return types, cobra.ShellCompDirectiveNoFileComp
}
+
+var containerStatuses = []string{"created", "running", "paused", "stopped", "exited", "unknown"}
+
+// 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(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(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
+ },
+ "label=": nil,
+ "exited=": nil,
+ "until=": nil,
+ }
+ return completeKeyValues(toComplete, kv)
+}
+
+// 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(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(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
+ },
+ "label=": nil,
+ }
+ 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..dc3202c7f 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"
@@ -136,7 +137,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
aliases []string
capAdd []string
cappDrop []string
- entrypoint string
+ entrypoint *string
init bool
specPorts []specgen.PortMapping
)
@@ -180,13 +181,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
}
}
@@ -321,7 +323,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
DeviceReadIOPs: readIops,
DeviceWriteBPs: writeBps,
DeviceWriteIOPs: writeIops,
- Entrypoint: &entrypoint,
+ Entrypoint: entrypoint,
Env: cc.Config.Env,
Expose: expose,
GroupAdd: cc.HostConfig.GroupAdd,
@@ -440,3 +442,66 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
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 642feb5e0..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) {
@@ -64,8 +82,7 @@ func listFlagSet(cmd *cobra.Command) {
filterFlagName := "filter"
flags.StringSliceVarP(&filters, filterFlagName, "f", []string{}, "Filter output based on conditions given")
- //TODO add custom filter function
- _ = cmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
+ _ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompletePsFilters)
formatFlagName := "format"
flags.StringVar(&listOpts.Format, formatFlagName, "", "Pretty-print containers to JSON or using a Go template")
diff --git a/cmd/podman/containers/top.go b/cmd/podman/containers/top.go
index 3eb6d2af2..f00b1dce1 100644
--- a/cmd/podman/containers/top.go
+++ b/cmd/podman/containers/top.go
@@ -18,12 +18,10 @@ import (
)
var (
- topDescription = `Similar to system "top" command.
-
- Specify format descriptors to alter the output.
-
- Running "podman top -l pid pcpu seccomp" will print the process ID, the CPU percentage and the seccomp mode of each process of the latest container.`
+ topDescription = `Display the running processes of a container.
+ The top command extends the ps(1) compatible AIX descriptors with container-specific ones as shown below. In the presence of ps(1) specific flags (e.g, -eo), Podman will execute ps(1) inside the container.
+`
topOptions = entities.TopOptions{}
topCommand = &cobra.Command{
diff --git a/cmd/podman/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/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/ps.go b/cmd/podman/pods/ps.go
index 51c2e92f0..99d324411 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -57,8 +57,7 @@ func init() {
filterFlagName := "filter"
flags.StringSliceVarP(&inputFilters, filterFlagName, "f", []string{}, "Filter output based on conditions given")
- //TODO complete filters
- _ = psCmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
+ _ = psCmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompletePodPsFilters)
formatFlagName := "format"
flags.StringVar(&psInput.Format, formatFlagName, "", "Pretty-print pods to JSON or using a Go template")
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/cirrus/cron-fail_addrs.csv b/contrib/cirrus/cron-fail_addrs.csv
new file mode 100644
index 000000000..c25fc1226
--- /dev/null
+++ b/contrib/cirrus/cron-fail_addrs.csv
@@ -0,0 +1 @@
+rh.container.bot@gmail.com
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/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-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-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..68a17d26b 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*
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/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..7a0bebd95 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -110,10 +110,15 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
podName := getCNIPodName(ctr)
- networks, err := ctr.networks()
+ networks, _, err := ctr.networks()
if err != nil {
return nil, err
}
+ // All networks have been removed from the container.
+ // This is effectively forcing net=none.
+ if len(networks) == 0 {
+ return nil, nil
+ }
// Update container map of interface descriptions
if err := ctr.setupNetworkDescriptions(networks); err != nil {
@@ -224,7 +229,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
if ctr.config.NetMode.IsSlirp4netns() {
return r.setupSlirp4netns(ctr)
}
- networks, err := ctr.networks()
+ networks, _, err := ctr.networks()
if err != nil {
return err
}
@@ -744,13 +749,13 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
- networks, err := ctr.networks()
+ networks, _, err := ctr.networks()
if err != nil {
return err
}
// rootless containers do not use the CNI plugin directly
- if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() {
+ if !rootless.IsRootless() && !ctr.config.NetMode.IsSlirp4netns() && len(networks) > 0 {
var requestedIP net.IP
if ctr.requestedIP != nil {
requestedIP = ctr.requestedIP
@@ -863,7 +868,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
settings := new(define.InspectNetworkSettings)
settings.Ports = makeInspectPortBindings(c.config.PortMappings)
- networks, err := c.networks()
+ networks, isDefault, err := c.networks()
if err != nil {
return nil, err
}
@@ -872,7 +877,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
if c.state.NetNS == nil {
// We still want to make dummy configurations for each CNI net
// the container joined.
- if len(networks) > 0 {
+ if len(networks) > 0 && !isDefault {
settings.Networks = make(map[string]*define.InspectAdditionalNetwork, len(networks))
for _, net := range networks {
cniNet := new(define.InspectAdditionalNetwork)
@@ -893,7 +898,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
}
// If we have CNI networks - handle that here
- if len(networks) > 0 {
+ if len(networks) > 0 && !isDefault {
if len(networks) != len(c.state.NetworkStatus) {
return nil, errors.Wrapf(define.ErrInternal, "network inspection mismatch: asked to join %d CNI networks but have information on %d networks", len(networks), len(c.state.NetworkStatus))
}
@@ -1101,7 +1106,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
return err
}
- ctrNetworks, err := c.networks()
+ ctrNetworks, _, err := c.networks()
if err != nil {
return err
}
diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go
index 1d6158cc2..2c2977f9f 100644
--- a/libpod/rootless_cni_linux.go
+++ b/libpod/rootless_cni_linux.go
@@ -40,7 +40,7 @@ const (
//
// AllocRootlessCNI does not lock c. c should be already locked.
func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.Result, error) {
- networks, err := c.networks()
+ networks, _, err := c.networks()
if err != nil {
return nil, nil, err
}
@@ -81,7 +81,7 @@ func AllocRootlessCNI(ctx context.Context, c *Container) (ns.NetNS, []*cnitypes.
//
// DeallocRootlessCNI does not lock c. c should be already locked.
func DeallocRootlessCNI(ctx context.Context, c *Container) error {
- networks, err := c.networks()
+ networks, _, err := c.networks()
if err != nil {
return err
}
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 00be8e845..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/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/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/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/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/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