summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/multi-arch-build.yaml181
-rw-r--r--cmd/podman/common/completion.go84
-rw-r--r--cmd/podman/common/completion_test.go142
-rw-r--r--cmd/podman/common/create_opts.go21
-rw-r--r--cmd/podman/containers/diff.go2
-rw-r--r--cmd/podman/containers/inspect.go8
-rw-r--r--cmd/podman/containers/mount.go2
-rw-r--r--cmd/podman/containers/ps.go2
-rw-r--r--cmd/podman/containers/stats.go2
-rw-r--r--cmd/podman/diff.go2
-rw-r--r--cmd/podman/generate/systemd.go2
-rw-r--r--cmd/podman/images/diff.go2
-rw-r--r--cmd/podman/images/history.go2
-rw-r--r--cmd/podman/images/inspect.go3
-rw-r--r--cmd/podman/images/list.go2
-rw-r--r--cmd/podman/images/mount.go2
-rw-r--r--cmd/podman/networks/inspect.go2
-rw-r--r--cmd/podman/networks/list.go2
-rw-r--r--cmd/podman/pods/inspect.go3
-rw-r--r--cmd/podman/pods/ps.go2
-rw-r--r--cmd/podman/pods/stats.go2
-rw-r--r--cmd/podman/secrets/inspect.go2
-rw-r--r--cmd/podman/secrets/list.go2
-rw-r--r--cmd/podman/system/events.go2
-rw-r--r--cmd/podman/system/info.go3
-rw-r--r--cmd/podman/system/version.go2
-rw-r--r--cmd/podman/volumes/inspect.go3
-rw-r--r--cmd/podman/volumes/list.go3
-rw-r--r--docs/source/markdown/podman-create.1.md1
-rw-r--r--docs/source/markdown/podman-run.1.md1
-rw-r--r--pkg/api/handlers/compat/containers.go12
-rw-r--r--test/compose/slirp4netns_opts/docker-compose.yml5
-rw-r--r--test/compose/slirp4netns_opts/setup.sh8
-rw-r--r--test/compose/slirp4netns_opts/teardown.sh4
-rw-r--r--test/compose/slirp4netns_opts/tests.sh6
35 files changed, 484 insertions, 40 deletions
diff --git a/.github/workflows/multi-arch-build.yaml b/.github/workflows/multi-arch-build.yaml
new file mode 100644
index 000000000..1781604fe
--- /dev/null
+++ b/.github/workflows/multi-arch-build.yaml
@@ -0,0 +1,181 @@
+name: build multi-arch images
+
+on:
+ # Upstream podman tends to be very active, with many merges per day.
+ # Only run this daily via cron schedule, or manually, not by branch push.
+ schedule:
+ - cron: '0 8 * * *'
+ # allows to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+jobs:
+ multi:
+ name: multi-arch Podman build
+ env:
+ PODMAN_QUAY_REGISTRY: quay.io/podman
+ CONTAINERS_QUAY_REGISTRY: quay.io/containers
+ # list of architectures for build
+ PLATFORMS: linux/amd64,linux/s390x,linux/ppc64le,linux/arm64
+
+ # build several images (upstream, testing, stable) in parallel
+ strategy:
+ matrix:
+ # Builds are located under contrib/podmanimage/<source> directory
+ source:
+ - upstream
+ - testing
+ - stable
+ runs-on: ubuntu-latest
+ # internal registry caches build for inspection before push
+ services:
+ registry:
+ image: quay.io/libpod/registry:2
+ ports:
+ - 5000:5000
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v1
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v1
+ with:
+ driver-opts: network=host
+ install: true
+
+ - name: Build and locally push Podman
+ uses: docker/build-push-action@v2
+ with:
+ context: contrib/podmanimage/${{ matrix.source }}
+ file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
+ platforms: ${{ env.PLATFORMS }}
+ push: true
+ tags: localhost:5000/podman/${{ matrix.source }}
+
+ # Simple verification that container works + grab version number
+ - name: amd64 container sniff test
+ id: sniff_test
+ run: |
+ VERSION_OUTPUT="$(docker run localhost:5000/podman/${{ matrix.source }} \
+ podman --storage-driver=vfs version)"
+ echo "$VERSION_OUTPUT"
+ VERSION=$(grep -Em1 '^Version: ' <<<"$VERSION_OUTPUT" | awk '{print $2}')
+ test -n "$VERSION"
+ echo "::set-output name=version::${VERSION}"
+
+ # Generate image FQINs, labels, check whether to push
+ - name: Generate image information
+ id: image_info
+ run: |
+ if [[ "${{ matrix.source }}" == 'stable' ]]; then
+ # quay.io/podman/stable:vX.X.X
+ ALLTAGS=$(skopeo list-tags \
+ docker://${{ env.PODMAN_QUAY_REGISTRY }}/stable | \
+ jq -r '.Tags[]')
+ PUSH="false"
+ if fgrep -qx "$VERSION" <<<"$ALLTAGS"; then
+ PUSH="true"
+ fi
+
+ FQIN='${{ env.PODMAN_QUAY_REGISTRY }}/stable:v${{ steps.sniff_test.outputs.version }}' # workaround vim syntax-hilighting bug: '
+ # Only push if version tag does not exist
+ if [[ "$PUSH" == "true" ]]; then
+ echo "Will push $FQIN"
+ echo "::set-output name=podman_push::${PUSH}"
+ echo "::set-output name=podman_fqin::${FQIN}"
+ fi
+
+ # quay.io/containers/podman:vX.X.X
+ unset ALLTAGS
+ ALLTAGS=$(skopeo list-tags \
+ docker://${{ env.CONTAINERS_QUAY_REGISTRY }}/podman | \
+ jq -r '.Tags[]')
+ PUSH="false"
+ if fgrep -qx "$VERSION" <<<"$ALLTAGS"; then
+ PUSH="true"
+ fi
+
+ FQIN='${{ env.CONTAINERS_QUAY_REGISTRY}}/podman:v${{ steps.sniff_test.outputs.version }}' # workaround vim syntax-hilighting bug: '
+ # Only push if version tag does not exist
+ if [[ "$PUSH" == "true" ]]; then
+ echo "Will push $FQIN"
+ echo "::set-output name=containers_push::${PUSH}"
+ echo "::set-output name=containers_fqin::$FQIN"
+ fi
+ else # upstream and testing podman image
+ P_FQIN='${{ env.PODMAN_QUAY_REGISTRY }}/${{ matrix.source }}:master' # workaround vim syntax-hilighting bug: '
+ C_FQIN='${{ env.CONTAINERS_QUAY_REGISTRY}}/podman:master' # workaround vim syntax-hilighting bug: '
+ echo "Will push $P_FQIN and $C_FQIN"
+ echo "::set-output name=podman_fqin::${P_FQIN}"
+ echo "::set-output name=containers_fqin::${C_FQIN}"
+ # Always push 'master' tag
+ echo '::set-output name=podman_push::true'
+ echo '::set-output name=containers_push::true'
+ fi
+
+ # Hack to set $LABELS env. var. in _future_ steps.
+ # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#multiline-strings
+ cat << EOF | tee $GITHUB_ENV
+ LABELS<<DELIMITER
+ org.opencontainers.image.source=https://github.com/${{ github.repository }}.git
+ org.opencontainers.image.revision=${{ github.sha }}
+ org.opencontainers.image.created=$(date -u --iso-8601=seconds)
+ DELIMITER
+ EOF
+
+ # Separate steps to login and push for podman and containers quay
+ # repositories are required, because 2 sets of credentials are used and `docker
+ # login` as well as `podman login` do not support having 2 different
+ # credential sets for 1 registry.
+ # At the same time reuse of non-shell steps is not supported by Github Actions
+ # via anchors or composite actions
+
+ # Push to 'podman' Quay repo for stable, testing. and upstream
+ - name: Login to 'podman' Quay registry
+ uses: docker/login-action@v1
+ if: ${{ steps.image_info.outputs.podman_push == 'true' }}
+ with:
+ registry: ${{ env.PODMAN_QUAY_REGISTRY }}
+ # N/B: Secrets are not passed to workflows that are triggered
+ # by a pull request from a fork
+ username: ${{ secrets.PODMAN_QUAY_USERNAME }}
+ password: ${{ secrets.PODMAN_QUAY_PASSWORD }}
+
+ - name: Push images to 'podman' Quay
+ uses: docker/build-push-action@v2
+ if: ${{ steps.image_info.outputs.podman_push == 'true' }}
+ with:
+ cache-from: type=registry,ref=localhost:5000/podman/${{ matrix.source }}
+ cache-to: type=inline
+ context: contrib/podmanimage/${{ matrix.source }}
+ file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
+ platforms: ${{ env.PLATFORMS }}
+ push: true
+ tags: ${{ steps.image_info.outputs.podman_fqin }}
+ labels: |
+ ${{ env.LABELS }}
+
+ # Push to 'containers' Quay repo only stable podman
+ - name: Login to 'containers' Quay registry
+ if: ${{ steps.image_info.outputs.containers_push == 'true' }}
+ uses: docker/login-action@v1
+ with:
+ registry: ${{ env.CONTAINERS_QUAY_REGISTRY}}
+ username: ${{ secrets.CONTAINERS_QUAY_USERNAME }}
+ password: ${{ secrets.CONTAINERS_QUAY_PASSWORD }}
+
+ - name: Push images to 'containers' Quay
+ if: ${{ steps.image_info.outputs.containers_push == 'true' }}
+ uses: docker/build-push-action@v2
+ with:
+ cache-from: type=registry,ref=localhost:5000/podman/${{ matrix.source }}
+ cache-to: type=inline
+ context: contrib/podmanimage/${{ matrix.source }}
+ file: ./contrib/podmanimage/${{ matrix.source }}/Dockerfile
+ platforms: ${{ env.PLATFORMS }}
+ push: true
+ tags: ${{ steps.image_info.outputs.containers_fqin }}
+ labels: |
+ ${{ env.LABELS }}
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 6086df297..4aca79770 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -4,6 +4,7 @@ import (
"bufio"
"fmt"
"os"
+ "reflect"
"strings"
"github.com/containers/common/pkg/config"
@@ -891,10 +892,85 @@ func AutocompleteNetworkFlag(cmd *cobra.Command, args []string, toComplete strin
return append(networks, suggestions...), dir
}
-// AutocompleteJSONFormat - Autocomplete format flag option.
-// -> "json"
-func AutocompleteJSONFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- return []string{"json"}, cobra.ShellCompDirectiveNoFileComp
+// AutocompleteFormat - Autocomplete json or a given struct to use for a go template.
+// The input can be nil, In this case only json will be autocompleted.
+// This function will only work for structs other types are not supported.
+// When "{{." is typed the field and method names of the given struct will be completed.
+// This also works recursive for nested structs.
+func AutocompleteFormat(o interface{}) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ // this function provides shell completion for go templates
+ return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ // autocomplete json when nothing or json is typed
+ if strings.HasPrefix("json", toComplete) {
+ return []string{"json"}, cobra.ShellCompDirectiveNoFileComp
+ }
+ // no input struct we cannot provide completion return nothing
+ if o == nil {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ // toComplete could look like this: {{ .Config }} {{ .Field.F
+ // 1. split the template variable delimiter
+ vars := strings.Split(toComplete, "{{")
+ if len(vars) == 1 {
+ // no variables return no completion
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+ // clean the spaces from the last var
+ field := strings.Split(vars[len(vars)-1], " ")
+ // split this into it struct field names
+ fields := strings.Split(field[len(field)-1], ".")
+ f := reflect.ValueOf(o)
+ for i := 1; i < len(fields); i++ {
+ if f.Kind() == reflect.Ptr {
+ f = f.Elem()
+ }
+
+ // // the only supported type is struct
+ if f.Kind() != reflect.Struct {
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
+
+ // last field get all names to suggest
+ if i == len(fields)-1 {
+ suggestions := []string{}
+ for j := 0; j < f.NumField(); j++ {
+ fname := f.Type().Field(j).Name
+ suffix := "}}"
+ kind := f.Type().Field(j).Type.Kind()
+ if kind == reflect.Ptr {
+ // make sure to read the actual type when it is a pointer
+ kind = f.Type().Field(j).Type.Elem().Kind()
+ }
+ // when we have a nested struct do not append braces instead append a dot
+ if kind == reflect.Struct {
+ suffix = "."
+ }
+ if strings.HasPrefix(fname, fields[i]) {
+ // add field name with closing braces
+ suggestions = append(suggestions, fname+suffix)
+ }
+ }
+
+ for j := 0; j < f.NumMethod(); j++ {
+ fname := f.Type().Method(j).Name
+ if strings.HasPrefix(fname, fields[i]) {
+ // add method name with closing braces
+ suggestions = append(suggestions, fname+"}}")
+ }
+ }
+
+ // add the current toComplete value in front so that the shell can complete this correctly
+ toCompArr := strings.Split(toComplete, ".")
+ toCompArr[len(toCompArr)-1] = ""
+ toComplete = strings.Join(toCompArr, ".")
+ return prefixSlice(toComplete, suggestions), cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveNoFileComp
+ }
+ // set the next struct field
+ f = f.FieldByName(fields[i])
+ }
+ return nil, cobra.ShellCompDirectiveNoFileComp
+ }
}
// AutocompleteEventFilter - Autocomplete event filter flag options.
diff --git a/cmd/podman/common/completion_test.go b/cmd/podman/common/completion_test.go
new file mode 100644
index 000000000..5bd627b85
--- /dev/null
+++ b/cmd/podman/common/completion_test.go
@@ -0,0 +1,142 @@
+package common_test
+
+import (
+ "testing"
+
+ "github.com/containers/podman/v3/cmd/podman/common"
+ "github.com/spf13/cobra"
+ "github.com/stretchr/testify/assert"
+)
+
+type Car struct {
+ Brand string
+ Stats struct {
+ HP *int
+ Displacement int
+ }
+ Extras map[string]string
+}
+
+func (c Car) Type() string {
+ return ""
+}
+
+func (c Car) Color() string {
+ return ""
+}
+
+func TestAutocompleteFormat(t *testing.T) {
+ testStruct := struct {
+ Name string
+ Age int
+ Car *Car
+ }{}
+
+ testStruct.Car = &Car{}
+ testStruct.Car.Extras = map[string]string{"test": "1"}
+
+ tests := []struct {
+ name string
+ toComplete string
+ expected []string
+ }{
+ {
+ "empty completion",
+ "",
+ []string{"json"},
+ },
+ {
+ "json completion",
+ "json",
+ []string{"json"},
+ },
+ {
+ "invalid completion",
+ "blahblah",
+ nil,
+ },
+ {
+ "invalid completion",
+ "{{",
+ nil,
+ },
+ {
+ "invalid completion",
+ "{{ ",
+ nil,
+ },
+ {
+ "invalid completion",
+ "{{ ..",
+ nil,
+ },
+ {
+ "fist level struct field name",
+ "{{.",
+ []string{"{{.Name}}", "{{.Age}}", "{{.Car."},
+ },
+ {
+ "fist level struct field name",
+ "{{ .",
+ []string{"{{ .Name}}", "{{ .Age}}", "{{ .Car."},
+ },
+ {
+ "fist level struct field name",
+ "{{ .N",
+ []string{"{{ .Name}}"},
+ },
+ {
+ "second level struct field name",
+ "{{ .Car.",
+ []string{"{{ .Car.Brand}}", "{{ .Car.Stats.", "{{ .Car.Extras}}", "{{ .Car.Color}}", "{{ .Car.Type}}"},
+ },
+ {
+ "second level struct field name",
+ "{{ .Car.B",
+ []string{"{{ .Car.Brand}}"},
+ },
+ {
+ "three level struct field name",
+ "{{ .Car.Stats.",
+ []string{"{{ .Car.Stats.HP}}", "{{ .Car.Stats.Displacement}}"},
+ },
+ {
+ "three level struct field name",
+ "{{ .Car.Stats.D",
+ []string{"{{ .Car.Stats.Displacement}}"},
+ },
+ {
+ "second level struct field name",
+ "{{ .Car.B",
+ []string{"{{ .Car.Brand}}"},
+ },
+ {
+ "invalid field name",
+ "{{ .Ca.B",
+ nil,
+ },
+ {
+ "map key names don't work",
+ "{{ .Car.Extras.",
+ nil,
+ },
+ {
+ "two variables struct field name",
+ "{{ .Car.Brand }} {{ .Car.",
+ []string{"{{ .Car.Brand }} {{ .Car.Brand}}", "{{ .Car.Brand }} {{ .Car.Stats.", "{{ .Car.Brand }} {{ .Car.Extras}}",
+ "{{ .Car.Brand }} {{ .Car.Color}}", "{{ .Car.Brand }} {{ .Car.Type}}"},
+ },
+ {
+ "only dot without variable",
+ ".",
+ nil,
+ },
+ }
+
+ for _, test := range tests {
+ completion, directive := common.AutocompleteFormat(testStruct)(nil, nil, test.toComplete)
+ // directive should always be greater than ShellCompDirectiveNoFileComp
+ assert.GreaterOrEqual(t, directive, cobra.ShellCompDirectiveNoFileComp, "unexpected ShellCompDirective")
+ assert.Equal(t, test.expected, completion, test.name)
+ }
+}
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 040dc6570..983b9e5ca 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -252,21 +252,24 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup
return nil, nil, err
}
- netNS := specgen.Namespace{
- NSMode: nsmode.NSMode,
- Value: nsmode.Value,
+ var netOpts map[string][]string
+ parts := strings.SplitN(string(cc.HostConfig.NetworkMode), ":", 2)
+ if len(parts) > 1 {
+ netOpts = make(map[string][]string)
+ netOpts[parts[0]] = strings.Split(parts[1], ",")
}
// network
// Note: we cannot emulate compat exactly here. we only allow specifics of networks to be
// defined when there is only one network.
netInfo := entities.NetOptions{
- AddHosts: cc.HostConfig.ExtraHosts,
- DNSOptions: cc.HostConfig.DNSOptions,
- DNSSearch: cc.HostConfig.DNSSearch,
- DNSServers: dns,
- Network: netNS,
- PublishPorts: specPorts,
+ AddHosts: cc.HostConfig.ExtraHosts,
+ DNSOptions: cc.HostConfig.DNSOptions,
+ DNSSearch: cc.HostConfig.DNSSearch,
+ DNSServers: dns,
+ Network: nsmode,
+ PublishPorts: specPorts,
+ NetworkOptions: netOpts,
}
// network names
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index f6f262066..799d01127 100644
--- a/cmd/podman/containers/diff.go
+++ b/cmd/podman/containers/diff.go
@@ -39,7 +39,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
- _ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
}
diff --git a/cmd/podman/containers/inspect.go b/cmd/podman/containers/inspect.go
index e7921fc39..eb29b7285 100644
--- a/cmd/podman/containers/inspect.go
+++ b/cmd/podman/containers/inspect.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/inspect"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -35,7 +36,12 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectContainerData{
+ State: &define.InspectContainerState{},
+ NetworkSettings: &define.InspectNetworkSettings{},
+ Config: &define.InspectContainerConfig{},
+ HostConfig: &define.InspectContainerHostConfig{},
+ }))
validate.AddLatestFlag(inspectCmd, &inspectOpts.Latest)
}
diff --git a/cmd/podman/containers/mount.go b/cmd/podman/containers/mount.go
index 7853bfae6..fd5a279d2 100644
--- a/cmd/podman/containers/mount.go
+++ b/cmd/podman/containers/mount.go
@@ -61,7 +61,7 @@ func mountFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&mountOpts.Format, formatFlagName, "", "Print the mounted containers in specified format (json)")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
flags.BoolVar(&mountOpts.NoTruncate, "notruncate", false, "Do not truncate output")
}
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 97451eb46..3c0162676 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -87,7 +87,7 @@ func listFlagSet(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&listOpts.Format, formatFlagName, "", "Pretty-print containers to JSON or using a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.ListContainer{}))
lastFlagName := "last"
flags.IntVarP(&listOpts.Last, lastFlagName, "n", -1, "Print the n last created containers (all states)")
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index 4c31896be..7160f1ba8 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -71,7 +71,7 @@ func statFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&statsOptions.Format, formatFlagName, "", "Pretty-print container statistics to JSON or using a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.ContainerStats{}))
flags.BoolVar(&statsOptions.NoReset, "no-reset", false, "Disable resetting the screen between intervals")
flags.BoolVar(&statsOptions.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result, default setting is false")
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 4862d31b5..ae7d6c4bc 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -43,7 +43,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
- _ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
validate.AddLatestFlag(diffCmd, &diffOpts.Latest)
}
diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go
index 693506725..72b2e6335 100644
--- a/cmd/podman/generate/systemd.go
+++ b/cmd/podman/generate/systemd.go
@@ -72,7 +72,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&format, formatFlagName, "", "Print the created units in specified format (json)")
- _ = systemdCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = systemdCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
flags.SetNormalizeFunc(utils.AliasFlags)
}
diff --git a/cmd/podman/images/diff.go b/cmd/podman/images/diff.go
index 36b0d4e7a..7f4c3e83d 100644
--- a/cmd/podman/images/diff.go
+++ b/cmd/podman/images/diff.go
@@ -41,7 +41,7 @@ func diffFlags(flags *pflag.FlagSet) {
formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format")
- _ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
}
func diff(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/images/history.go b/cmd/podman/images/history.go
index eaf56651f..16be0bb19 100644
--- a/cmd/podman/images/history.go
+++ b/cmd/podman/images/history.go
@@ -74,7 +74,7 @@ func historyFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&opts.format, formatFlagName, "", "Change the output to JSON or a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.ImageHistoryLayer{}))
flags.BoolVarP(&opts.human, "human", "H", true, "Display sizes and dates in human readable format")
flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate the output")
diff --git a/cmd/podman/images/inspect.go b/cmd/podman/images/inspect.go
index fb96286fa..ac3becaa6 100644
--- a/cmd/podman/images/inspect.go
+++ b/cmd/podman/images/inspect.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/inspect"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/pkg/domain/entities"
+ inspectTypes "github.com/containers/podman/v3/pkg/inspect"
"github.com/spf13/cobra"
)
@@ -34,7 +35,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(inspectTypes.ImageData{}))
}
func inspectExec(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/images/list.go b/cmd/podman/images/list.go
index 7a9a8a804..132af858b 100644
--- a/cmd/podman/images/list.go
+++ b/cmd/podman/images/list.go
@@ -83,7 +83,7 @@ func imageListFlagSet(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "", "Change the output format to JSON or a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.ImageSummary{}))
flags.BoolVar(&listFlag.digests, "digests", false, "Show digests")
flags.BoolVarP(&listFlag.noHeading, "noheading", "n", false, "Do not print column headings")
diff --git a/cmd/podman/images/mount.go b/cmd/podman/images/mount.go
index 79c97006d..a098aac63 100644
--- a/cmd/podman/images/mount.go
+++ b/cmd/podman/images/mount.go
@@ -51,7 +51,7 @@ func mountFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVar(&mountOpts.Format, formatFlagName, "", "Print the mounted images in specified format (json)")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
}
func init() {
diff --git a/cmd/podman/networks/inspect.go b/cmd/podman/networks/inspect.go
index 953f5e6e8..a05b9026d 100644
--- a/cmd/podman/networks/inspect.go
+++ b/cmd/podman/networks/inspect.go
@@ -33,7 +33,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "", "Pretty-print network to JSON or using a Go template")
- _ = networkinspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = networkinspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
}
func networkInspect(_ *cobra.Command, args []string) error {
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go
index bc100da8c..e1b182cbf 100644
--- a/cmd/podman/networks/list.go
+++ b/cmd/podman/networks/list.go
@@ -41,7 +41,7 @@ var (
func networkListFlags(flags *pflag.FlagSet) {
formatFlagName := "format"
flags.StringVar(&networkListOptions.Format, formatFlagName, "", "Pretty-print networks to JSON or using a Go template")
- _ = networklistCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = networklistCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPrintReports{}))
flags.BoolVarP(&networkListOptions.Quiet, "quiet", "q", false, "display only names")
flags.BoolVar(&noTrunc, "no-trunc", false, "Do not truncate the network ID")
diff --git a/cmd/podman/pods/inspect.go b/cmd/podman/pods/inspect.go
index 96e007fa3..c66b81adb 100644
--- a/cmd/podman/pods/inspect.go
+++ b/cmd/podman/pods/inspect.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -44,7 +45,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOptions.Format, formatFlagName, "f", "json", "Format the output to a Go template or json")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectPodData{}))
validate.AddLatestFlag(inspectCmd, &inspectOptions.Latest)
}
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index a4b6d1afa..beaeda871 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -61,7 +61,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&psInput.Format, formatFlagName, "", "Pretty-print pods to JSON or using a Go template")
- _ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = psCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(ListPodReporter{}))
flags.Bool("noheading", false, "Do not print headers")
flags.BoolVar(&psInput.Namespace, "namespace", false, "Display namespace information of the pod")
diff --git a/cmd/podman/pods/stats.go b/cmd/podman/pods/stats.go
index e336b864e..97147275e 100644
--- a/cmd/podman/pods/stats.go
+++ b/cmd/podman/pods/stats.go
@@ -58,7 +58,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&statsOptions.Format, formatFlagName, "", "Pretty-print container statistics to JSON or using a Go template")
- _ = statsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = statsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.PodStatsReport{}))
flags.BoolVar(&statsOptions.NoReset, "no-reset", false, "Disable resetting the screen when streaming")
flags.BoolVar(&statsOptions.NoStream, "no-stream", false, "Disable streaming stats and only pull the first result")
diff --git a/cmd/podman/secrets/inspect.go b/cmd/podman/secrets/inspect.go
index 4036291ec..bcb1adb5e 100644
--- a/cmd/podman/secrets/inspect.go
+++ b/cmd/podman/secrets/inspect.go
@@ -40,7 +40,7 @@ func init() {
flags := inspectCmd.Flags()
formatFlagName := "format"
flags.StringVar(&format, formatFlagName, "", "Format volume output using Go template")
- _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.SecretInfoReport{}))
}
func inspect(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go
index 2006fb0ee..ba7065d61 100644
--- a/cmd/podman/secrets/list.go
+++ b/cmd/podman/secrets/list.go
@@ -47,7 +47,7 @@ func init() {
flags := lsCmd.Flags()
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}\t\n", "Format volume output using Go template")
- _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.SecretInfoReport{}))
flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers")
}
diff --git a/cmd/podman/system/events.go b/cmd/podman/system/events.go
index 0f52282a9..568610bdc 100644
--- a/cmd/podman/system/events.go
+++ b/cmd/podman/system/events.go
@@ -52,7 +52,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&eventFormat, formatFlagName, "", "format the output using a Go template")
- _ = eventsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = eventsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(events.Event{}))
flags.BoolVar(&eventOptions.Stream, "stream", true, "stream new events; for testing only")
diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go
index 2babd49c8..afd5b3a34 100644
--- a/cmd/podman/system/info.go
+++ b/cmd/podman/system/info.go
@@ -10,6 +10,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
@@ -68,7 +69,7 @@ func infoFlags(cmd *cobra.Command) {
formatFlagName := "format"
flags.StringVarP(&inFormat, formatFlagName, "f", "", "Change the output format to JSON or a Go template")
- _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = cmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.Info{Host: &define.HostInfo{}, Store: &define.StoreInfo{}}))
}
func info(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index dfb10c080..ad9fd2a85 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -38,7 +38,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&versionFormat, formatFlagName, "f", "", "Change the output format to JSON or a Go template")
- _ = versionCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = versionCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(entities.SystemVersionReport{}))
}
func version(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/volumes/inspect.go b/cmd/podman/volumes/inspect.go
index 91269e3d1..d52eee9f3 100644
--- a/cmd/podman/volumes/inspect.go
+++ b/cmd/podman/volumes/inspect.go
@@ -4,6 +4,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/inspect"
"github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -41,7 +42,7 @@ func init() {
formatFlagName := "format"
flags.StringVarP(&inspectOpts.Format, formatFlagName, "f", "json", "Format volume output using Go template")
- _ = inspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = inspectCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectVolumeData{}))
}
func volumeInspect(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go
index 0d764e988..f402afa94 100644
--- a/cmd/podman/volumes/list.go
+++ b/cmd/podman/volumes/list.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/parse"
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -60,7 +61,7 @@ func init() {
formatFlagName := "format"
flags.StringVar(&cliOpts.Format, formatFlagName, "{{.Driver}}\t{{.Name}}\n", "Format volume output using Go template")
- _ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
+ _ = lsCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(define.InspectVolumeData{}))
flags.Bool("noheading", false, "Do not print headers")
flags.BoolVarP(&cliOpts.Quiet, "quiet", "q", false, "Print volume output in quiet mode")
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 1ea9d1ea6..229bb82f5 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -1365,6 +1365,7 @@ $ podman create --name container1 -t -i fedora bash
$ podman create --name container2 -t -i fedora bash
$ podman create --name container3 --requires container1,container2 -t -i fedora bash
$ podman start --attach container3
+```
### Configure keep supplemental groups for access to volume
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 3a2651f98..2e6d97a05 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -1719,6 +1719,7 @@ Multiple containers can be required.
$ podman create --name container1 -t -i fedora bash
$ podman create --name container2 -t -i fedora bash
$ podman run --name container3 --requires container1,container2 -t -i fedora bash
+```
### Configure keep supplemental groups for access to volume
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index e7146a5d8..d97a4d3bd 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -26,6 +26,7 @@ import (
"github.com/docker/go-units"
"github.com/gorilla/schema"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
func RemoveContainer(w http.ResponseWriter, r *http.Request) {
@@ -148,14 +149,19 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
containers = containers[:query.Limit]
}
}
- var list = make([]*handlers.Container, len(containers))
- for i, ctnr := range containers {
+ list := make([]*handlers.Container, 0, len(containers))
+ for _, ctnr := range containers {
api, err := LibpodToContainer(ctnr, query.Size)
if err != nil {
+ if errors.Cause(err) == define.ErrNoSuchCtr {
+ // container was removed between the initial fetch of the list and conversion
+ logrus.Debugf("Container %s removed between initial fetch and conversion, ignoring in output", ctnr.ID())
+ continue
+ }
utils.InternalServerError(w, err)
return
}
- list[i] = api
+ list = append(list, api)
}
utils.WriteResponse(w, http.StatusOK, list)
}
diff --git a/test/compose/slirp4netns_opts/docker-compose.yml b/test/compose/slirp4netns_opts/docker-compose.yml
new file mode 100644
index 000000000..dcdcae04c
--- /dev/null
+++ b/test/compose/slirp4netns_opts/docker-compose.yml
@@ -0,0 +1,5 @@
+services:
+ alpine:
+ image: alpine
+ network_mode: "slirp4netns:allow_host_loopback=true"
+ command: sh -c "echo teststring | nc 10.0.2.2 5001"
diff --git a/test/compose/slirp4netns_opts/setup.sh b/test/compose/slirp4netns_opts/setup.sh
new file mode 100644
index 000000000..35bbf7c70
--- /dev/null
+++ b/test/compose/slirp4netns_opts/setup.sh
@@ -0,0 +1,8 @@
+# -*- bash -*-
+
+# create tempfile to store nc output
+OUTFILE=$(mktemp)
+# listen on a port, the container will try to connect to it
+nc -l 5001 > $OUTFILE &
+
+nc_pid=$!
diff --git a/test/compose/slirp4netns_opts/teardown.sh b/test/compose/slirp4netns_opts/teardown.sh
new file mode 100644
index 000000000..656724363
--- /dev/null
+++ b/test/compose/slirp4netns_opts/teardown.sh
@@ -0,0 +1,4 @@
+# -*- bash -*-
+
+kill $nc_pid &> /dev/null
+rm -f $OUTFILE
diff --git a/test/compose/slirp4netns_opts/tests.sh b/test/compose/slirp4netns_opts/tests.sh
new file mode 100644
index 000000000..1efce45c4
--- /dev/null
+++ b/test/compose/slirp4netns_opts/tests.sh
@@ -0,0 +1,6 @@
+# -*- bash -*-
+
+output="$(cat $OUTFILE)"
+expected="teststring"
+
+is "$output" "$expected" "$testname : nc received teststring"