mirror of https://github.com/containers/podman.git
Fix broken podman images filters
The id, digest, and intermediate filters were broken for podman images. Fix to match on substrings instead of the whole string for id and digest. Add the intermediate value correctly when set. Signed-off-by: Urvashi Mohnani <umohnani@redhat.com>
This commit is contained in:
parent
87dd939334
commit
ba788c1bb8
4
go.mod
4
go.mod
|
@ -13,7 +13,7 @@ require (
|
|||
github.com/containernetworking/cni v1.1.2
|
||||
github.com/containernetworking/plugins v1.3.0
|
||||
github.com/containers/buildah v1.32.0
|
||||
github.com/containers/common v0.56.1-0.20230927174306-9342cdd82aa6
|
||||
github.com/containers/common v0.56.1-0.20230929120646-4fd26cf84f19
|
||||
github.com/containers/conmon v2.0.20+incompatible
|
||||
github.com/containers/gvisor-tap-vsock v0.7.1
|
||||
github.com/containers/image/v5 v5.28.0
|
||||
|
@ -45,7 +45,7 @@ require (
|
|||
github.com/moby/term v0.5.0
|
||||
github.com/nxadm/tail v1.4.8
|
||||
github.com/onsi/ginkgo/v2 v2.12.1
|
||||
github.com/onsi/gomega v1.27.10
|
||||
github.com/onsi/gomega v1.28.0
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5
|
||||
github.com/opencontainers/runc v1.1.9
|
||||
|
|
8
go.sum
8
go.sum
|
@ -249,8 +249,8 @@ github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q
|
|||
github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0=
|
||||
github.com/containers/buildah v1.32.0 h1:uz5Rcf7lGeStj7iPTBgO4UdhQYZqMMzyt9suDf16k1k=
|
||||
github.com/containers/buildah v1.32.0/go.mod h1:sN3rA3DbnqekNz3bNdkqWduuirYDuMs54LUCOZOomBE=
|
||||
github.com/containers/common v0.56.1-0.20230927174306-9342cdd82aa6 h1:yALmokSK/0EKa12wV4AkgLr7ObDIo5sySJohDhE2UIs=
|
||||
github.com/containers/common v0.56.1-0.20230927174306-9342cdd82aa6/go.mod h1:ABFEglmyt48WWWQv80kGhitfbVfR1Br35wk3gBQdrIk=
|
||||
github.com/containers/common v0.56.1-0.20230929120646-4fd26cf84f19 h1:aAs/BiCzeNndwOTt0tnE26D4B4wtztVxl/4h0bu86qY=
|
||||
github.com/containers/common v0.56.1-0.20230929120646-4fd26cf84f19/go.mod h1:yV1LzHyQ4KH99zPS4NA0cfKdZKG3RHjozjsiT0GPsIg=
|
||||
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/gvisor-tap-vsock v0.7.1 h1:+Rc+sOPplrkQb/BUXeN0ug8TxjgyrIqo/9P/eNS2A4c=
|
||||
|
@ -807,8 +807,8 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
|
|||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
|
||||
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
|
||||
github.com/onsi/gomega v1.28.0 h1:i2rg/p9n/UqIDAMFUJ6qIUUMcsqOuUHgbpbu235Vr1c=
|
||||
github.com/onsi/gomega v1.28.0/go.mod h1:A1H2JE76sI14WIP57LMKj7FVfCHx3g3BcZVjJG8bjX8=
|
||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/containers/common/libimage"
|
||||
"github.com/containers/podman/v4/libpod/define"
|
||||
"github.com/containers/podman/v4/pkg/domain/entities"
|
||||
"github.com/containers/podman/v4/pkg/util"
|
||||
)
|
||||
|
||||
func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
|
||||
|
@ -14,7 +15,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions)
|
|||
Filters: opts.Filter,
|
||||
SetListData: true,
|
||||
}
|
||||
if !opts.All {
|
||||
if !opts.All && !util.StringInSlice("intermediate=true", listImagesOptions.Filters) {
|
||||
// Filter intermediate images unless we want to list *all*.
|
||||
// NOTE: it's a positive filter, so `intermediate=false` means
|
||||
// to display non-intermediate images.
|
||||
|
|
|
@ -118,6 +118,32 @@ var _ = Describe("Podman images", func() {
|
|||
Expect(session.OutputToStringArray()).To(HaveLen(2))
|
||||
})
|
||||
|
||||
It("podman images filter by image ID", func() {
|
||||
session := podmanTest.Podman([]string{"inspect", ALPINE, "--format", "{{.ID}}"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitCleanly())
|
||||
Expect(session.OutputToStringArray()).To(HaveLen(1))
|
||||
imgID := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"images", "--noheading", "--filter", "id=" + imgID[:5]})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitCleanly())
|
||||
Expect(session.OutputToStringArray()).To(HaveLen(1))
|
||||
})
|
||||
|
||||
It("podman images filter by image digest", func() {
|
||||
session := podmanTest.Podman([]string{"inspect", ALPINE, "--format", "{{.Digest}}"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitCleanly())
|
||||
Expect(session.OutputToStringArray()).To(HaveLen(1))
|
||||
imgDigest := session.OutputToString()
|
||||
|
||||
session = podmanTest.Podman([]string{"images", "--noheading", "--filter", "digest=" + imgDigest[:10]})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session).Should(ExitCleanly())
|
||||
Expect(session.OutputToStringArray()).To(HaveLen(1))
|
||||
})
|
||||
|
||||
It("podman images filter reference", func() {
|
||||
result := podmanTest.Podman([]string{"images", "-q", "-f", "reference=quay.io/libpod/*"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
|
@ -195,6 +221,18 @@ WORKDIR /test
|
|||
Expect(result.OutputToStringArray()).Should(BeEmpty(), "dangling image output: %q", result.OutputToString())
|
||||
})
|
||||
|
||||
It("podman images filter intermediate", func() {
|
||||
dockerfile := `FROM quay.io/libpod/alpine:latest
|
||||
RUN touch /tmp/test.txt
|
||||
RUN touch /tmp/test-2.txt
|
||||
`
|
||||
podmanTest.BuildImage(dockerfile, "foobar.com/test-build", "true")
|
||||
result := podmanTest.Podman([]string{"images", "--noheading", "--filter", "intermediate=true"})
|
||||
result.WaitWithDefaultTimeout()
|
||||
Expect(result).Should(ExitCleanly())
|
||||
Expect(result.OutputToStringArray()).To(HaveLen(1))
|
||||
})
|
||||
|
||||
It("podman pull by digest and list --all", func() {
|
||||
// Prevent regressing on issue #7651: error parsing name that includes a digest
|
||||
// component as if were a name that includes tag component.
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
filtersPkg "github.com/containers/common/pkg/filters"
|
||||
"github.com/containers/common/pkg/timetype"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -394,18 +393,17 @@ func filterDangling(ctx context.Context, value bool, tree *layerTree) filterFunc
|
|||
// filterID creates an image-ID filter for matching the specified value.
|
||||
func filterID(value string) filterFunc {
|
||||
return func(img *Image) (bool, error) {
|
||||
return img.ID() == value, nil
|
||||
return strings.HasPrefix(img.ID(), value), nil
|
||||
}
|
||||
}
|
||||
|
||||
// filterDigest creates a digest filter for matching the specified value.
|
||||
func filterDigest(value string) (filterFunc, error) {
|
||||
d, err := digest.Parse(value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid value %q for digest filter: %w", value, err)
|
||||
if !strings.HasPrefix(value, "sha256:") {
|
||||
return nil, fmt.Errorf("invalid value %q for digest filter", value)
|
||||
}
|
||||
return func(img *Image) (bool, error) {
|
||||
return img.hasDigest(d), nil
|
||||
return img.containsDigestPrefix(value), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -169,6 +169,17 @@ func (i *Image) hasDigest(wantedDigest digest.Digest) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// containsDigestPrefix returns whether the specified value matches any digest of the
|
||||
// image. It checks for the prefix and not a full match.
|
||||
func (i *Image) containsDigestPrefix(wantedDigestPrefix string) bool {
|
||||
for _, d := range i.Digests() {
|
||||
if strings.HasPrefix(d.String(), wantedDigestPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsReadOnly returns whether the image is set read only.
|
||||
func (i *Image) IsReadOnly() bool {
|
||||
return i.storageImage.ReadOnly
|
||||
|
|
|
@ -440,6 +440,8 @@ func (m *ManifestList) Push(ctx context.Context, destination string, options *Ma
|
|||
SignSigstorePrivateKeyPassphrase: options.SignSigstorePrivateKeyPassphrase,
|
||||
RemoveSignatures: options.RemoveSignatures,
|
||||
ManifestType: options.ManifestMIMEType,
|
||||
MaxRetries: options.MaxRetries,
|
||||
RetryDelay: options.RetryDelay,
|
||||
ForceCompressionFormat: options.ForceCompressionFormat,
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,10 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/containers/common/pkg/manifests"
|
||||
"github.com/containers/common/pkg/retry"
|
||||
"github.com/containers/common/pkg/supplemented"
|
||||
cp "github.com/containers/image/v5/copy"
|
||||
"github.com/containers/image/v5/docker/reference"
|
||||
|
@ -27,6 +29,10 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxRetries = 3
|
||||
)
|
||||
|
||||
const instancesData = "instances.json"
|
||||
|
||||
// LookupReferenceFunc return an image reference based on the specified one.
|
||||
|
@ -72,6 +78,11 @@ type PushOptions struct {
|
|||
SourceFilter LookupReferenceFunc // filter the list source
|
||||
AddCompression []string // add existing instances with requested compression algorithms to manifest list
|
||||
ForceCompressionFormat bool // force push with requested compression ignoring the blobs which can be reused.
|
||||
// Maximum number of retries with exponential backoff when facing
|
||||
// transient network errors. Default 3.
|
||||
MaxRetries *uint
|
||||
// RetryDelay used for the exponential back off of MaxRetries.
|
||||
RetryDelay *time.Duration
|
||||
}
|
||||
|
||||
// Create creates a new list containing information about the specified image,
|
||||
|
@ -262,16 +273,31 @@ func (l *list) Push(ctx context.Context, dest types.ImageReference, options Push
|
|||
ForceCompressionFormat: options.ForceCompressionFormat,
|
||||
}
|
||||
|
||||
retryOptions := retry.Options{}
|
||||
retryOptions.MaxRetry = defaultMaxRetries
|
||||
if options.MaxRetries != nil {
|
||||
retryOptions.MaxRetry = int(*options.MaxRetries)
|
||||
}
|
||||
if options.RetryDelay != nil {
|
||||
retryOptions.Delay = *options.RetryDelay
|
||||
}
|
||||
|
||||
// Copy whatever we were asked to copy.
|
||||
manifestBytes, err := cp.Image(ctx, policyContext, dest, src, copyOptions)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
var manifestDigest digest.Digest
|
||||
f := func() error {
|
||||
opts := copyOptions
|
||||
var manifestBytes []byte
|
||||
var digest digest.Digest
|
||||
var err error
|
||||
if manifestBytes, err = cp.Image(ctx, policyContext, dest, src, opts); err == nil {
|
||||
if digest, err = manifest.Digest(manifestBytes); err == nil {
|
||||
manifestDigest = digest
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
manifestDigest, err := manifest.Digest(manifestBytes)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return nil, manifestDigest, nil
|
||||
err = retry.IfNecessary(ctx, f, &retryOptions)
|
||||
return nil, manifestDigest, err
|
||||
}
|
||||
|
||||
func prepareAddWithCompression(variants []string) ([]cp.OptionCompressionVariant, error) {
|
||||
|
|
|
@ -204,7 +204,10 @@ func (n *netavarkNetwork) networkCreate(newNetwork *types.Network, defaultNet bo
|
|||
}
|
||||
// rust only support "true" or "false" while go can parse 1 and 0 as well so we need to change it
|
||||
newNetwork.Options[types.NoDefaultRoute] = strconv.FormatBool(val)
|
||||
|
||||
case types.VRFOption:
|
||||
if len(value) == 0 {
|
||||
return nil, errors.New("invalid vrf name")
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported bridge network option %s", key)
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ const (
|
|||
MetricOption = "metric"
|
||||
NoDefaultRoute = "no_default_route"
|
||||
BclimOption = "bclim"
|
||||
VRFOption = "vrf"
|
||||
)
|
||||
|
||||
type NetworkBackend string
|
||||
|
|
|
@ -67,7 +67,7 @@ func createPruneFilterFuncs(key string, filterValues []string) (types.FilterFunc
|
|||
}, nil
|
||||
case "label!":
|
||||
return func(net types.Network) bool {
|
||||
return !filters.MatchLabelFilters(filterValues, net.Labels)
|
||||
return filters.MatchNegatedLabelFilters(filterValues, net.Labels)
|
||||
}, nil
|
||||
case "until":
|
||||
until, err := filters.ComputeUntilTimestamp(filterValues)
|
||||
|
|
|
@ -362,6 +362,35 @@ func addFIPSModeSubscription(mounts *[]rspec.Mount, containerRunDir, mountPoint,
|
|||
}
|
||||
*mounts = append(*mounts, m)
|
||||
}
|
||||
|
||||
// Make sure we set the config to FIPS so that the container does not overwrite
|
||||
// /etc/crypto-policies/back-ends when crypto-policies-scripts is reinstalled.
|
||||
cryptoPoliciesConfigFile := filepath.Join(containerRunDir, "fips-config")
|
||||
file, err := os.Create(cryptoPoliciesConfigFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating fips config file in container for FIPS mode: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := file.WriteString("FIPS\n"); err != nil {
|
||||
return fmt.Errorf("writing fips config file in container for FIPS mode: %w", err)
|
||||
}
|
||||
if err = label.Relabel(cryptoPoliciesConfigFile, mountLabel, false); err != nil {
|
||||
return fmt.Errorf("applying correct labels on fips-config file: %w", err)
|
||||
}
|
||||
if err := file.Chown(uid, gid); err != nil {
|
||||
return fmt.Errorf("chown fips-config file: %w", err)
|
||||
}
|
||||
|
||||
policyConfig := "/etc/crypto-policies/config"
|
||||
if !mountExists(*mounts, policyConfig) {
|
||||
m := rspec.Mount{
|
||||
Source: cryptoPoliciesConfigFile,
|
||||
Destination: policyConfig,
|
||||
Type: "bind",
|
||||
Options: []string{"bind", "rprivate"},
|
||||
}
|
||||
*mounts = append(*mounts, m)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
## 1.28.0
|
||||
|
||||
### Features
|
||||
- Add VerifyHost handler to ghttp (#698) [0b03b36]
|
||||
|
||||
### Fixes
|
||||
- Read Body for Newer Responses in HaveHTTPBodyMatcher (#686) [18d6673]
|
||||
|
||||
### Maintenance
|
||||
- Bump github.com/onsi/ginkgo/v2 from 2.11.0 to 2.12.0 (#693) [55a33f3]
|
||||
- Typo in matchers.go (#691) [de68e8f]
|
||||
- Bump commonmarker from 0.23.9 to 0.23.10 in /docs (#690) [ab17f5e]
|
||||
- chore: update test matrix for Go 1.21 (#689) [5069017]
|
||||
- Bump golang.org/x/net from 0.12.0 to 0.14.0 (#688) [babe25f]
|
||||
|
||||
## 1.27.10
|
||||
|
||||
### Fixes
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
"github.com/onsi/gomega/types"
|
||||
)
|
||||
|
||||
const GOMEGA_VERSION = "1.27.10"
|
||||
const GOMEGA_VERSION = "1.28.0"
|
||||
|
||||
const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
|
||||
If you're using Ginkgo then you probably forgot to put your assertion in an It().
|
||||
|
|
|
@ -94,7 +94,7 @@ func Succeed() types.GomegaMatcher {
|
|||
//
|
||||
// Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
|
||||
// Expect(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual)
|
||||
// Expect(err).Should(MatchError(ContainSubstring("sprocket not found"))) // asserts that edrr.Error() contains substring "sprocket not found"
|
||||
// Expect(err).Should(MatchError(ContainSubstring("sprocket not found"))) // asserts that err.Error() contains substring "sprocket not found"
|
||||
//
|
||||
// It is an error for err to be nil or an object that does not implement the
|
||||
// Error interface
|
||||
|
|
|
@ -11,8 +11,9 @@ import (
|
|||
)
|
||||
|
||||
type HaveHTTPBodyMatcher struct {
|
||||
Expected interface{}
|
||||
cachedBody []byte
|
||||
Expected interface{}
|
||||
cachedResponse interface{}
|
||||
cachedBody []byte
|
||||
}
|
||||
|
||||
func (matcher *HaveHTTPBodyMatcher) Match(actual interface{}) (bool, error) {
|
||||
|
@ -73,7 +74,7 @@ func (matcher *HaveHTTPBodyMatcher) NegatedFailureMessage(actual interface{}) (m
|
|||
// the Reader is closed and it is not readable again in FailureMessage()
|
||||
// or NegatedFailureMessage()
|
||||
func (matcher *HaveHTTPBodyMatcher) body(actual interface{}) ([]byte, error) {
|
||||
if matcher.cachedBody != nil {
|
||||
if matcher.cachedResponse == actual && matcher.cachedBody != nil {
|
||||
return matcher.cachedBody, nil
|
||||
}
|
||||
|
||||
|
@ -91,8 +92,10 @@ func (matcher *HaveHTTPBodyMatcher) body(actual interface{}) ([]byte, error) {
|
|||
|
||||
switch a := actual.(type) {
|
||||
case *http.Response:
|
||||
matcher.cachedResponse = a
|
||||
return body(a)
|
||||
case *httptest.ResponseRecorder:
|
||||
matcher.cachedResponse = a
|
||||
return body(a.Result())
|
||||
default:
|
||||
return nil, fmt.Errorf("HaveHTTPBody matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n%s", format.Object(actual, 1))
|
||||
|
|
|
@ -164,7 +164,7 @@ github.com/containers/buildah/pkg/sshagent
|
|||
github.com/containers/buildah/pkg/util
|
||||
github.com/containers/buildah/pkg/volumes
|
||||
github.com/containers/buildah/util
|
||||
# github.com/containers/common v0.56.1-0.20230927174306-9342cdd82aa6
|
||||
# github.com/containers/common v0.56.1-0.20230929120646-4fd26cf84f19
|
||||
## explicit; go 1.18
|
||||
github.com/containers/common/libimage
|
||||
github.com/containers/common/libimage/define
|
||||
|
@ -797,7 +797,7 @@ github.com/onsi/ginkgo/v2/internal/parallel_support
|
|||
github.com/onsi/ginkgo/v2/internal/testingtproxy
|
||||
github.com/onsi/ginkgo/v2/reporters
|
||||
github.com/onsi/ginkgo/v2/types
|
||||
# github.com/onsi/gomega v1.27.10
|
||||
# github.com/onsi/gomega v1.28.0
|
||||
## explicit; go 1.18
|
||||
github.com/onsi/gomega
|
||||
github.com/onsi/gomega/format
|
||||
|
|
Loading…
Reference in New Issue