diff options
-rw-r--r-- | cmd/podman/common/completion.go | 27 | ||||
-rw-r--r-- | cmd/podman/networks/list.go | 6 | ||||
-rw-r--r-- | cmd/podman/secrets/list.go | 16 | ||||
-rw-r--r-- | cmd/podman/volumes/list.go | 13 | ||||
-rw-r--r-- | cmd/podman/volumes/prune.go | 3 | ||||
-rw-r--r-- | docs/source/markdown/podman-secret-ls.1.md | 13 | ||||
-rw-r--r-- | docs/tutorials/mac_win_client.md | 6 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 3 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_build.go | 8 | ||||
-rw-r--r-- | pkg/domain/filters/containers.go | 18 | ||||
-rw-r--r-- | pkg/domain/filters/pods.go | 20 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 2 | ||||
-rw-r--r-- | pkg/network/network.go | 27 | ||||
-rw-r--r-- | test/apiv2/10-images.at | 76 | ||||
-rw-r--r-- | test/apiv2/35-networks.at | 2 | ||||
-rw-r--r-- | test/apiv2/README.md | 6 | ||||
-rwxr-xr-x | test/apiv2/test-apiv2 | 31 | ||||
-rw-r--r-- | test/e2e/secret_test.go | 49 | ||||
-rw-r--r-- | test/system/500-networking.bats | 15 | ||||
-rw-r--r-- | utils/utils.go | 6 | ||||
-rw-r--r-- | vendor/modules.txt | 2 |
22 files changed, 217 insertions, 134 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index cb3efe592..f1dea4113 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -13,7 +13,6 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/network/types" "github.com/containers/podman/v3/pkg/domain/entities" - "github.com/containers/podman/v3/pkg/network" "github.com/containers/podman/v3/pkg/rootless" systemdDefine "github.com/containers/podman/v3/pkg/systemd/define" "github.com/containers/podman/v3/pkg/util" @@ -209,7 +208,7 @@ func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellComp return suggestions, cobra.ShellCompDirectiveNoFileComp } -func getSecrets(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) { +func getSecrets(cmd *cobra.Command, toComplete string, cType completeType) ([]string, cobra.ShellCompDirective) { suggestions := []string{} engine, err := setupContainerEngine(cmd) @@ -224,7 +223,13 @@ func getSecrets(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCom } for _, s := range secrets { - if strings.HasPrefix(s.Spec.Name, toComplete) { + // works the same as in getNetworks + if ((len(toComplete) > 1 && cType == completeDefault) || + cType == completeIDs) && strings.HasPrefix(s.ID, toComplete) { + suggestions = append(suggestions, s.ID[0:12]) + } + // include name in suggestions + if cType != completeIDs && strings.HasPrefix(s.Spec.Name, toComplete) { suggestions = append(suggestions, s.Spec.Name) } } @@ -256,12 +261,11 @@ func getNetworks(cmd *cobra.Command, toComplete string, cType completeType) ([]s } for _, n := range networks { - id := network.GetNetworkID(n.Name) // 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(id, toComplete) { - suggestions = append(suggestions, id[0:12]) + cType == completeIDs) && strings.HasPrefix(n.ID, toComplete) { + suggestions = append(suggestions, n.ID[0:12]) } // include name in suggestions if cType != completeIDs && strings.HasPrefix(n.Name, toComplete) { @@ -470,7 +474,7 @@ func AutocompleteSecrets(cmd *cobra.Command, args []string, toComplete string) ( if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getSecrets(cmd, toComplete) + return getSecrets(cmd, toComplete, completeDefault) } func AutocompleteSecretCreate(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { @@ -1283,6 +1287,15 @@ func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete str return completeKeyValues(toComplete, kv) } +// AutocompleteSecretFilters - Autocomplete secret ls --filter options. +func AutocompleteSecretFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + kv := keyValueCompletion{ + "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getSecrets(cmd, s, completeNames) }, + "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getSecrets(cmd, s, completeIDs) }, + } + return completeKeyValues(toComplete, kv) +} + // AutocompleteCheckpointCompressType - Autocomplete checkpoint compress type options. // -> "gzip", "none", "zstd" func AutocompleteCheckpointCompressType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go index 6f1a7742a..7ce566225 100644 --- a/cmd/podman/networks/list.go +++ b/cmd/podman/networks/list.go @@ -3,6 +3,7 @@ package network import ( "fmt" "os" + "sort" "strings" "github.com/containers/common/pkg/completion" @@ -73,6 +74,11 @@ func networkList(cmd *cobra.Command, args []string) error { return err } + // sort the networks to make sure the order is deterministic + sort.Slice(responses, func(i, j int) bool { + return responses[i].Name < responses[j].Name + }) + switch { // quiet means we only print the network names case networkListOptions.Quiet: diff --git a/cmd/podman/secrets/list.go b/cmd/podman/secrets/list.go index 255d9ae1a..2074ab973 100644 --- a/cmd/podman/secrets/list.go +++ b/cmd/podman/secrets/list.go @@ -8,6 +8,7 @@ import ( "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/report" "github.com/containers/podman/v3/cmd/podman/common" + "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/pkg/domain/entities" @@ -32,6 +33,7 @@ var ( type listFlagType struct { format string noHeading bool + filter []string } func init() { @@ -44,14 +46,26 @@ func init() { 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.AutocompleteFormat(entities.SecretInfoReport{})) + filterFlagName := "filter" + flags.StringSliceVarP(&listFlag.filter, filterFlagName, "f", []string{}, "Filter secret output") + _ = lsCmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteSecretFilters) flags.BoolVar(&listFlag.noHeading, "noheading", false, "Do not print headers") } func ls(cmd *cobra.Command, args []string) error { - responses, err := registry.ContainerEngine().SecretList(context.Background(), entities.SecretListRequest{}) + var err error + lsOpts := entities.SecretListRequest{} + + lsOpts.Filters, err = parse.FilterArgumentsIntoFilters(listFlag.filter) + if err != nil { + return err + } + + responses, err := registry.ContainerEngine().SecretList(context.Background(), lsOpts) if err != nil { return err } + listed := make([]*entities.SecretListReport, 0, len(responses)) for _, response := range responses { listed = append(listed, &entities.SecretListReport{ diff --git a/cmd/podman/volumes/list.go b/cmd/podman/volumes/list.go index c372527de..97fa2c61f 100644 --- a/cmd/podman/volumes/list.go +++ b/cmd/podman/volumes/list.go @@ -4,11 +4,11 @@ import ( "context" "fmt" "os" - "strings" "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/report" "github.com/containers/podman/v3/cmd/podman/common" + "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" @@ -64,19 +64,18 @@ func init() { } func list(cmd *cobra.Command, args []string) error { + var err error if cliOpts.Quiet && cmd.Flag("format").Changed { return errors.New("quiet and format flags cannot be used together") } if len(cliOpts.Filter) > 0 { lsOpts.Filter = make(map[string][]string) } - for _, f := range cliOpts.Filter { - filterSplit := strings.SplitN(f, "=", 2) - if len(filterSplit) < 2 { - return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) - } - lsOpts.Filter[filterSplit[0]] = append(lsOpts.Filter[filterSplit[0]], filterSplit[1]) + lsOpts.Filter, err = parse.FilterArgumentsIntoFilters(cliOpts.Filter) + if err != nil { + return err } + responses, err := registry.ContainerEngine().VolumeList(context.Background(), lsOpts) if err != nil { return err diff --git a/cmd/podman/volumes/prune.go b/cmd/podman/volumes/prune.go index 1f3cc6913..43b529768 100644 --- a/cmd/podman/volumes/prune.go +++ b/cmd/podman/volumes/prune.go @@ -58,6 +58,9 @@ func prune(cmd *cobra.Command, args []string) error { return err } pruneOptions.Filters, err = parse.FilterArgumentsIntoFilters(filter) + if err != nil { + return err + } if !force { reader := bufio.NewReader(os.Stdin) fmt.Println("WARNING! This will remove all volumes not used by at least one container. The following volumes will be removed:") diff --git a/docs/source/markdown/podman-secret-ls.1.md b/docs/source/markdown/podman-secret-ls.1.md index 27576f026..f33ccf41b 100644 --- a/docs/source/markdown/podman-secret-ls.1.md +++ b/docs/source/markdown/podman-secret-ls.1.md @@ -20,11 +20,24 @@ Format secret output using Go template. Omit the table headings from the listing of secrets. . +#### **--filter**, **-f**=*filter=value* + +Filter output based on conditions given. +Multiple filters can be given with multiple uses of the --filter option. + +Valid filters are listed below: + +| **Filter** | **Description** | +| ---------- | ----------------------------------------------------------------- | +| name | [Name] Secret name (accepts regex) | +| id | [ID] Full or partial secret ID | + ## EXAMPLES ``` $ podman secret ls $ podman secret ls --format "{{.Name}}" +$ podman secret ls --filter name=confidential ``` ## SEE ALSO diff --git a/docs/tutorials/mac_win_client.md b/docs/tutorials/mac_win_client.md index 6295eb6b2..159296d5e 100644 --- a/docs/tutorials/mac_win_client.md +++ b/docs/tutorials/mac_win_client.md @@ -12,11 +12,11 @@ The remote client uses a client-server model. You need Podman installed on a Lin ### Windows -Installing the Windows Podman client begins by downloading the Podman windows installer. The windows installer is built with each Podman release and is downloadable from its [release description page](https://github.com/containers/podman/releases/latest). You can also build the installer from source using the `podman.msi` Makefile endpoint. +Installing the Windows Podman client begins by downloading the Podman Windows installer. The Windows installer is built with each Podman release and is downloadable from its [release description page](https://github.com/containers/podman/releases/latest). The Windows installer file is named `podman-v.#.#.#.msi`, where the `#` symbols represent the version number of Podman. At the time of this writing, the file name is `podman-v3.4.4.msi`. You can also build the installer from source using the `podman.msi` Makefile endpoint. -Once you have downloaded the installer, simply double click the installer and Podman will be installed. The path is also set to put `podman` in the default user path. +Once you have downloaded the installer to your Windows host, simply double click the installer and Podman will be installed. The path is also set to put `podman` in the default user path. -Podman must be run at a command prompt using the Windows ‘cmd” or powershell applications. +Podman must be run at a command prompt using the Windows Command Prompt (`cmd.exe`) or PowerShell (`pwsh.exe`) applications. ### macOS @@ -24,7 +24,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/digitalocean/go-qemu v0.0.0-20210209191958-152a1535e49f github.com/docker/distribution v2.7.1+incompatible - github.com/docker/docker v20.10.11+incompatible + github.com/docker/docker v20.10.12+incompatible github.com/docker/go-connections v0.4.0 github.com/docker/go-plugins-helpers v0.0.0-20200102110956-c9a8a2d92ccc github.com/docker/go-units v0.4.0 @@ -344,8 +344,9 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v20.10.11+incompatible h1:OqzI/g/W54LczvhnccGqniFoQghHx3pklbLuhfXpqGo= github.com/docker/docker v20.10.11+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U= +github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.4 h1:axCks+yV+2MR3/kZhAmy07yC56WZ2Pwu/fKWtKuZB0o= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index a665be4fb..45e4543a9 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -621,7 +621,8 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { Stream string `json:"stream,omitempty"` Error *jsonmessage.JSONError `json:"errorDetail,omitempty"` // NOTE: `error` is being deprecated check https://github.com/moby/moby/blob/master/pkg/jsonmessage/jsonmessage.go#L148 - ErrorMessage string `json:"error,omitempty"` // deprecate this slowly + ErrorMessage string `json:"error,omitempty"` // deprecate this slowly + Aux json.RawMessage `json:"aux,omitempty"` }{} select { @@ -656,6 +657,11 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { case <-runCtx.Done(): if success { if !utils.IsLibpodRequest(r) && !query.Quiet { + m.Aux = []byte(fmt.Sprintf(`{"ID":"sha256:%s"}`, imageID)) + if err := enc.Encode(m); err != nil { + logrus.Warnf("failed to json encode error %v", err) + } + m.Aux = nil m.Stream = fmt.Sprintf("Successfully built %12.12s\n", imageID) if err := enc.Encode(m); err != nil { logrus.Warnf("Failed to json encode error %v", err) diff --git a/pkg/domain/filters/containers.go b/pkg/domain/filters/containers.go index bd5167fa5..60a1efb22 100644 --- a/pkg/domain/filters/containers.go +++ b/pkg/domain/filters/containers.go @@ -8,7 +8,6 @@ import ( "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" - "github.com/containers/podman/v3/pkg/network" "github.com/containers/podman/v3/pkg/util" "github.com/pkg/errors" ) @@ -210,6 +209,15 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo return false }, nil case "network": + var inputNetNames []string + for _, val := range filterValues { + net, err := r.Network().NetworkInspect(val) + if err != nil { + // ignore not found errors + break + } + inputNetNames = append(inputNetNames, net.Name) + } return func(c *libpod.Container) bool { networkMode := c.NetworkMode() // support docker like `--filter network=container:<IDorName>` @@ -247,12 +255,8 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo return false } for _, net := range networks { - netID := network.GetNetworkID(net) - for _, val := range filterValues { - // match by network name or id - if val == net || val == netID { - return true - } + if util.StringInSlice(net, inputNetNames) { + return true } } return false diff --git a/pkg/domain/filters/pods.go b/pkg/domain/filters/pods.go index 59a6d0d78..8231dbc79 100644 --- a/pkg/domain/filters/pods.go +++ b/pkg/domain/filters/pods.go @@ -6,7 +6,6 @@ import ( "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" - "github.com/containers/podman/v3/pkg/network" "github.com/containers/podman/v3/pkg/util" "github.com/pkg/errors" ) @@ -14,7 +13,7 @@ import ( // GeneratePodFilterFunc takes a filter and filtervalue (key, value) // and generates a libpod function that can be used to filter // pods -func GeneratePodFilterFunc(filter string, filterValues []string) ( +func GeneratePodFilterFunc(filter string, filterValues []string, r *libpod.Runtime) ( func(pod *libpod.Pod) bool, error) { switch filter { case "ctr-ids": @@ -128,6 +127,15 @@ func GeneratePodFilterFunc(filter string, filterValues []string) ( return false }, nil case "network": + var inputNetNames []string + for _, val := range filterValues { + net, err := r.Network().NetworkInspect(val) + if err != nil { + // ignore not found errors + break + } + inputNetNames = append(inputNetNames, net.Name) + } return func(p *libpod.Pod) bool { infra, err := p.InfraContainer() // no infra, quick out @@ -140,12 +148,8 @@ func GeneratePodFilterFunc(filter string, filterValues []string) ( return false } for _, net := range networks { - netID := network.GetNetworkID(net) - for _, val := range filterValues { - // match by network name or id - if val == net || val == netID { - return true - } + if util.StringInSlice(net, inputNetNames) { + return true } } return false diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index c8c7b0d9e..7bda7e994 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -325,7 +325,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti filters := make([]libpod.PodFilter, 0, len(options.Filters)) for k, v := range options.Filters { - f, err := dfilters.GeneratePodFilterFunc(k, v) + f, err := dfilters.GeneratePodFilterFunc(k, v, ic.Libpod) if err != nil { return nil, err } diff --git a/pkg/network/network.go b/pkg/network/network.go deleted file mode 100644 index 44132ca28..000000000 --- a/pkg/network/network.go +++ /dev/null @@ -1,27 +0,0 @@ -package network - -import ( - "crypto/sha256" - "encoding/hex" - "strings" - - "github.com/containernetworking/cni/libcni" -) - -// GetCNIPlugins returns a list of plugins that a given network -// has in the form of a string -func GetCNIPlugins(list *libcni.NetworkConfigList) string { - plugins := make([]string, 0, len(list.Plugins)) - for _, plug := range list.Plugins { - plugins = append(plugins, plug.Network.Type) - } - return strings.Join(plugins, ",") -} - -// GetNetworkID return the network ID for a given name. -// It is just the sha256 hash but this should be good enough. -// The caller has to make sure it is only called with the network name. -func GetNetworkID(name string) string { - hash := sha256.Sum256([]byte(name)) - return hex.EncodeToString(hash[:]) -} diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at index 85d4d69ed..f849fc33c 100644 --- a/test/apiv2/10-images.at +++ b/test/apiv2/10-images.at @@ -171,70 +171,32 @@ function cleanBuildTest() { } CONTAINERFILE_TAR="${TMPD}/containerfile.tar" cat > $TMPD/containerfile << EOF -FROM quay.io/libpod/alpine_labels:latest +FROM $IMAGE EOF tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_TAR} containerfile &> /dev/null -curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \ - -H "content-type: application/x-tar" \ - --dump-header "${TMPD}/headers.txt" \ - -o "${TMPD}/response.txt" \ - "http://$HOST:$PORT/v1.40/libpod/build?dockerfile=containerfile" &> /dev/null - -BUILD_TEST_ERROR="" - -if ! grep -q '200 OK' "${TMPD}/headers.txt"; then - echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/x-tar)" - BUILD_TEST_ERROR="1" -fi - -if ! grep -q 'quay.io/libpod/alpine_labels' "${TMPD}/response.txt"; then - echo -e "${red}NOK: Image build from tar failed image name not in response" - BUILD_TEST_ERROR="1" -fi - -curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \ - -H "content-type: application/tar" \ - --dump-header "${TMPD}/headers.txt" \ - -o "${TMPD}/response.txt" \ - "http://$HOST:$PORT/v1.40/build?dockerfile=containerfile&q=true" &> /dev/null -if ! grep -q '200 OK' "${TMPD}/headers.txt"; then - echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/tar)" - BUILD_TEST_ERROR="1" -fi -if grep -E "\"[0-9a-f]{64}\\\n\"" $(jq .stream "${TMPD}/response.txt"); then - echo -e "${red} quiet-mode should only send image ID" - BUILD_TEST_ERROR="1" -fi - -# Yes, this is very un-RESTful re: Content-Type header ignored when compatibility endpoint used -# See https://github.com/containers/podman/issues/11012 -curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \ - -H "content-type: application/json" \ - --dump-header "${TMPD}/headers.txt" \ - -o /dev/null \ - "http://$HOST:$PORT/v1.40/build?dockerfile=containerfile" &> /dev/null -if ! grep -q '200 OK' "${TMPD}/headers.txt"; then - echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/tar)" - BUILD_TEST_ERROR="1" -fi - -curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \ - -H "content-type: application/json" \ - --dump-header "${TMPD}/headers.txt" \ - -o /dev/null \ - "http://$HOST:$PORT/v1.40/libpod/build?dockerfile=containerfile" &> /dev/null -if ! grep -q '400 Bad Request' "${TMPD}/headers.txt"; then - echo -e "${red}NOK: Image build should have failed with 400 (wrong Content-Type)" - BUILD_TEST_ERROR="1" -fi +t POST "libpod/build?dockerfile=containerfile" $CONTAINERFILE_TAR 200 \ + .stream~"STEP 1/1: FROM $IMAGE" + +# With -q, all we should get is image ID. Test both libpod & compat endpoints. +t POST "libpod/build?dockerfile=containerfile&q=true" $CONTAINERFILE_TAR 200 \ + .stream~'^[0-9a-f]\{64\}$' +t POST "build?dockerfile=containerfile&q=true" $CONTAINERFILE_TAR 200 \ + .stream~'^[0-9a-f]\{64\}$' + +# Override content-type and confirm that libpod rejects, but compat accepts +t POST "libpod/build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 400 \ + .cause='Content-Type: application/json is not supported. Should be "application/x-tar"' +t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200 \ + .stream~"STEP 1/1: FROM $IMAGE" + +# PR #12091: output from compat API must now include {"aux":{"ID":"sha..."}} +t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR 200 \ + '.aux|select(has("ID")).ID~^sha256:[0-9a-f]\{64\}$' t POST libpod/images/prune 200 t POST libpod/images/prune 200 length=0 [] cleanBuildTest -if [[ "${BUILD_TEST_ERROR}" ]]; then - exit 1 -fi # vim: filetype=sh diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at index 713f677fa..0e2389bd5 100644 --- a/test/apiv2/35-networks.at +++ b/test/apiv2/35-networks.at @@ -7,7 +7,7 @@ t GET networks/non-existing-network 404 \ .cause='network not found' t POST libpod/networks/create name='"network1"' 200 \ - .name=network1 + .name=network1 \ .created~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \ # --data '{"name":"network2","subnets":[{"subnet":"10.10.254.0/24"}],"Labels":{"abc":"val"}}' diff --git a/test/apiv2/README.md b/test/apiv2/README.md index 19727cec7..63d1f5b13 100644 --- a/test/apiv2/README.md +++ b/test/apiv2/README.md @@ -60,6 +60,12 @@ of POST parameters in the form 'key=value', separated by spaces: t POST myentrypoint name=$name badparam='["foo","bar"]' 500 ! etc... `t` will convert the param list to JSON form for passing to the server. A numeric status code terminates processing of POST parameters. +** As a special case, when one POST argument is a string ending in `.tar`, +`t` will invoke `curl` with `--data-binary @PATH` and +set `Content-type: application/x-tar`. This is useful for `build` endpoints. +(To override `Content-type`, simply pass along an extra string argument +matching `application/*`): + t POST myentrypoint /mytmpdir/myfile.tar application/foo 400 * The final arguments are one or more expected string results. If an argument starts with a dot, `t` will invoke `jq` on the output to diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2 index c644b9578..47934cca9 100755 --- a/test/apiv2/test-apiv2 +++ b/test/apiv2/test-apiv2 @@ -182,6 +182,7 @@ function t() { local method=$1; shift local path=$1; shift local curl_args + local content_type="application/json" local testname="$method $path" # POST requests may be followed by one or more key=value pairs. @@ -190,13 +191,21 @@ function t() { local -a post_args for arg; do case "$arg" in - *=*) post_args+=("$arg"); shift ;; + *=*) post_args+=("$arg"); + shift;; + *.tar) curl_args="--data-binary @$arg" ; + content_type="application/x-tar"; + shift;; + application/*) content_type="$arg"; + shift;; [1-9][0-9][0-9]) break;; *) die "Internal error: invalid POST arg '$arg'" ;; esac done - curl_args="-d $(jsonify ${post_args[@]})" - testname="$testname [$curl_args]" + if [[ -z "$curl_args" ]]; then + curl_args="-d $(jsonify ${post_args[@]})" + testname="$testname [$curl_args]" + fi fi # entrypoint path can include a descriptive comment; strip it off @@ -229,7 +238,7 @@ function t() { rm -f $WORKDIR/curl.* # -s = silent, but --write-out 'format' gives us important response data response=$(curl -s -X $method ${curl_args} \ - -H 'Content-type: application/json' \ + -H "Content-type: $content_type" \ --dump-header $WORKDIR/curl.headers.out \ --write-out '%{http_code}^%{content_type}^%{time_total}' \ -o $WORKDIR/curl.result.out "$url") @@ -328,10 +337,13 @@ function start_service() { fi echo $WORKDIR - $PODMAN_BIN --root $WORKDIR/server_root --syslog=true \ - system service \ - --time 15 \ - tcp:127.0.0.1:$PORT \ + # Some tests use shortnames; force registry override to work around + # docker.io throttling. + env CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf $PODMAN_BIN \ + --root $WORKDIR/server_root --syslog=true \ + system service \ + --time 15 \ + tcp:127.0.0.1:$PORT \ &> $WORKDIR/server.log & service_pid=$! @@ -460,7 +472,8 @@ function wait_for_port() { ############ function podman() { echo "\$ $PODMAN_BIN $*" >>$WORKDIR/output.log - $PODMAN_BIN --root $WORKDIR/server_root "$@" >>$WORKDIR/output.log 2>&1 + env CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf \ + $PODMAN_BIN --root $WORKDIR/server_root "$@" >>$WORKDIR/output.log 2>&1 } #################### diff --git a/test/e2e/secret_test.go b/test/e2e/secret_test.go index 661ebbdc0..f08638b1b 100644 --- a/test/e2e/secret_test.go +++ b/test/e2e/secret_test.go @@ -1,6 +1,7 @@ package integration import ( + "fmt" "io/ioutil" "os" "path/filepath" @@ -145,6 +146,54 @@ var _ = Describe("Podman secret", func() { }) + It("podman secret ls with filters", func() { + secretFilePath := filepath.Join(podmanTest.TempDir, "secret") + err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755) + Expect(err).To(BeNil()) + + secret1 := "Secret1" + secret2 := "Secret2" + + session := podmanTest.Podman([]string{"secret", "create", secret1, secretFilePath}) + session.WaitWithDefaultTimeout() + secrID1 := session.OutputToString() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"secret", "create", secret2, secretFilePath}) + session.WaitWithDefaultTimeout() + secrID2 := session.OutputToString() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"secret", "create", "Secret3", secretFilePath}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + list := podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("name=%s", secret1)}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secret1)) + + list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("name=%s", secret2)}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secret2)) + + list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("id=%s", secrID1)}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secrID1)) + + list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("id=%s", secrID2)}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secrID2)) + + list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("name=%s,name=%s", secret1, secret2)}) + list.WaitWithDefaultTimeout() + Expect(list).Should(Exit(0)) + Expect(list.OutputToStringArray()).To(HaveLen(3), ContainSubstring(secret1), ContainSubstring(secret2)) + }) + It("podman secret ls with Go template", func() { secretFilePath := filepath.Join(podmanTest.TempDir, "secret") err := ioutil.WriteFile(secretFilePath, []byte("mysecret"), 0755) diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index deadfa90a..4d36163d7 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -16,6 +16,21 @@ load helpers if [[ ${output} = ${heading} ]]; then die "network ls --noheading did not remove heading: $output" fi + + # check deterministic list order + local net1=a-$(random_string 10) + local net2=b-$(random_string 10) + local net3=c-$(random_string 10) + run_podman network create $net1 + run_podman network create $net2 + run_podman network create $net3 + + run_podman network ls --quiet + # just check the the order of the created networks is correct + # we cannot do an exact match since developer and CI systems could contain more networks + is "$output" ".*$net1.*$net2.*$net3.*podman.*" "networks sorted alphabetically" + + run_podman network rm $net1 $net2 $net3 } # Copied from tsweeney's https://github.com/containers/podman/issues/4827 diff --git a/utils/utils.go b/utils/utils.go index 095370a08..241e361cd 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/containers/common/pkg/cgroups" "github.com/containers/podman/v3/libpod/define" @@ -204,8 +205,9 @@ func moveProcessToScope(pidPath, slice, scope string) error { func MovePauseProcessToScope(pausePidPath string) { var err error - for i := 0; i < 3; i++ { - r := rand.Int() + state := rand.New(rand.NewSource(time.Now().UnixNano())) + for i := 0; i < 10; i++ { + r := state.Int() err = moveProcessToScope(pausePidPath, "user.slice", fmt.Sprintf("podman-pause-%d.scope", r)) if err == nil { return diff --git a/vendor/modules.txt b/vendor/modules.txt index 3109a6698..1976528fe 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -311,7 +311,7 @@ github.com/docker/distribution/registry/client/auth/challenge github.com/docker/distribution/registry/client/transport github.com/docker/distribution/registry/storage/cache github.com/docker/distribution/registry/storage/cache/memory -# github.com/docker/docker v20.10.11+incompatible +# github.com/docker/docker v20.10.12+incompatible ## explicit github.com/docker/docker/api github.com/docker/docker/api/types |