Merge pull request #20192 from umohnani8/images

Fix broken podman images filters
This commit is contained in:
openshift-ci[bot]
2023-10-02 17:49:40 +00:00
committed by GitHub
17 changed files with 157 additions and 30 deletions

4
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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.

View File

@ -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.

View File

@ -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
}

View File

@ -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

View File

@ -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,
}

View File

@ -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) {

View File

@ -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)
}

View File

@ -43,6 +43,7 @@ const (
MetricOption = "metric"
NoDefaultRoute = "no_default_route"
BclimOption = "bclim"
VRFOption = "vrf"
)
type NetworkBackend string

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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().

View File

@ -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

View File

@ -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))

4
vendor/modules.txt vendored
View File

@ -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