diff --git a/cmd/buildah/images.go b/cmd/buildah/images.go index 4e31039905a..f0dc5f257a0 100644 --- a/cmd/buildah/images.go +++ b/cmd/buildah/images.go @@ -252,7 +252,7 @@ func formatImages(images []*libimage.Image, opts imageOptions) error { outputParam.Size = formattedSize(size) outputParam.ReadOnly = image.IsReadOnly() - repoTags, err := image.NamedTaggedRepoTags() + repoTags, err := image.NamedRepoTags() if err != nil { return err } diff --git a/cmd/buildah/manifest.go b/cmd/buildah/manifest.go index c2067946dca..2f62d26b076 100644 --- a/cmd/buildah/manifest.go +++ b/cmd/buildah/manifest.go @@ -21,6 +21,7 @@ import ( "github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/types" "github.com/containers/storage" + "github.com/hashicorp/go-multierror" digest "github.com/opencontainers/go-digest" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -462,14 +463,21 @@ func manifestRmCmd(c *cobra.Command, args []string) error { options := &libimage.RemoveImagesOptions{ Filters: []string{"readonly=false"}, } - untagged, removed, err := runtime.RemoveImages(context.Background(), args, options) - for _, u := range untagged { - fmt.Printf("untagged: %s\n", u) + rmiReports, rmiErrors := runtime.RemoveImages(context.Background(), args, options) + for _, r := range rmiReports { + for _, u := range r.Untagged { + fmt.Printf("untagged: %s\n", u) + } } - for _, r := range removed { - fmt.Printf("%s\n", r) + for _, r := range rmiReports { + if r.Removed { + fmt.Printf("%s\n", r.ID) + } } - return err + + var multiE *multierror.Error + multiE = multierror.Append(multiE, rmiErrors...) + return multiE.ErrorOrNil() } func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateOpts) error { diff --git a/cmd/buildah/rmi.go b/cmd/buildah/rmi.go index 8a06b981448..699b703a31a 100644 --- a/cmd/buildah/rmi.go +++ b/cmd/buildah/rmi.go @@ -7,6 +7,7 @@ import ( buildahcli "github.com/containers/buildah/pkg/cli" "github.com/containers/buildah/pkg/parse" "github.com/containers/common/libimage" + "github.com/hashicorp/go-multierror" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -87,12 +88,19 @@ func rmiCmd(c *cobra.Command, args []string, iopts rmiOptions) error { } options.Force = iopts.force - untagged, removed, err := runtime.RemoveImages(context.Background(), args, options) - for _, u := range untagged { - fmt.Printf("untagged: %s\n", u) + rmiReports, rmiErrors := runtime.RemoveImages(context.Background(), args, options) + for _, r := range rmiReports { + for _, u := range r.Untagged { + fmt.Printf("untagged: %s\n", u) + } } - for _, r := range removed { - fmt.Printf("%s\n", r) + for _, r := range rmiReports { + if r.Removed { + fmt.Printf("%s\n", r.ID) + } } - return err + + var multiE *multierror.Error + multiE = multierror.Append(multiE, rmiErrors...) + return multiE.ErrorOrNil() } diff --git a/go.mod b/go.mod index 4bbb40ae161..40723ce2ff2 100644 --- a/go.mod +++ b/go.mod @@ -40,3 +40,5 @@ require ( ) replace github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.4.2 + +replace github.com/containers/common => github.com/vrothberg/common v0.0.3-0.20210430070256-9bc69171635f diff --git a/go.sum b/go.sum index cdd86054dd4..575039f0d3c 100644 --- a/go.sum +++ b/go.sum @@ -178,8 +178,6 @@ github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ github.com/containernetworking/cni v0.8.1 h1:7zpDnQ3T3s4ucOuJ/ZCLrYBxzkg0AELFfII3Epo9TmI= github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= -github.com/containers/common v0.37.0 h1:RRyR8FITTJXfrF7J9KXKSplywY4zsXoA2kuQXMaUaNo= -github.com/containers/common v0.37.0/go.mod h1:dgbJcccCPTmncqxhma56+XW+6d5VzqGF6jtkMHyu3v0= github.com/containers/image/v5 v5.11.1 h1:mNybUvU6zXUwcMsQaa3n+Idsru5pV+GE7k4oRuPzYi0= github.com/containers/image/v5 v5.11.1/go.mod h1:HC9lhJ/Nz5v3w/5Co7H431kLlgzlVlOC+auD/er3OqE= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE= @@ -223,6 +221,8 @@ github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8l github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/disiqueira/gotree/v3 v3.0.2 h1:ik5iuLQQoufZBNPY518dXhiO5056hyNBIK9lWhkNRq8= +github.com/disiqueira/gotree/v3 v3.0.2/go.mod h1:ZuyjE4+mUQZlbpkI24AmruZKhg3VHEgPLDY8Qk+uUu8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -687,6 +687,8 @@ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYp github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vrothberg/common v0.0.3-0.20210430070256-9bc69171635f h1:k+3j9Xko0KFRUxAEjaoCg66/pwR4w5AjMcUzfqCetkw= +github.com/vrothberg/common v0.0.3-0.20210430070256-9bc69171635f/go.mod h1:4jx2zI23wh9Jj1ozFeFHG7RoXzcU8acoADIKOLJX7BA= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index 1f5a2810de7..160a56498dc 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -318,13 +318,14 @@ func (b *Executor) resolveNameToImageRef(output string) (types.ImageReference, e return nil, err } // If we can resolve the image locally, make sure we use the resolved name. - localImage, resolvedName, err := runtime.LookupImage(output, nil) + _, resolvedName, err := runtime.LookupImage(output, nil) if err != nil { - return nil, err - } - if localImage != nil { + if errors.Cause(err) != storage.ErrImageUnknown { + return nil, err + } output = resolvedName } + // If we cannot find an image, make sure we normalize the name // according the conventions and rules in libimage (e.g., // "localhost/" prefixing). diff --git a/new.go b/new.go index 004132f5953..a68dc57a511 100644 --- a/new.go +++ b/new.go @@ -9,7 +9,7 @@ import ( "github.com/containers/buildah/define" "github.com/containers/buildah/pkg/blobcache" "github.com/containers/common/libimage" - libimageTypes "github.com/containers/common/libimage/types" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/image" "github.com/containers/image/v5/manifest" "github.com/containers/image/v5/transports" @@ -119,7 +119,7 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions return nil, err } - pullPolicy, err := libimageTypes.ParsePullPolicy(options.PullPolicy.String()) + pullPolicy, err := config.ParsePullPolicy(options.PullPolicy.String()) if err != nil { return nil, err } diff --git a/pull.go b/pull.go index 618996e19c1..7149ac98631 100644 --- a/pull.go +++ b/pull.go @@ -8,7 +8,7 @@ import ( "github.com/containers/buildah/define" "github.com/containers/buildah/pkg/blobcache" "github.com/containers/common/libimage" - libimageTypes "github.com/containers/common/libimage/types" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/types" encconfig "github.com/containers/ocicrypt/config" "github.com/containers/storage" @@ -73,7 +73,7 @@ func Pull(ctx context.Context, imageName string, options PullOptions) (imageID s libimageOptions.DestinationLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal) } - pullPolicy, err := libimageTypes.ParsePullPolicy(options.PullPolicy.String()) + pullPolicy, err := config.ParsePullPolicy(options.PullPolicy.String()) if err != nil { return "", err } diff --git a/util/util.go b/util/util.go index 3d1744b813c..3b22a394347 100644 --- a/util/util.go +++ b/util/util.go @@ -173,9 +173,6 @@ func FindImage(store storage.Store, firstRegistry string, systemContext *types.S if err != nil { return nil, nil, err } - if localImage == nil { - return nil, nil, errors.Wrap(storage.ErrImageUnknown, image) - } ref, err := localImage.StorageReference() if err != nil { return nil, nil, err @@ -227,9 +224,6 @@ func AddImageNames(store storage.Store, firstRegistry string, systemContext *typ if err != nil { return err } - if localImage == nil { - return errors.Errorf("could not find libimage for %s", image.ID) - } for _, tag := range addNames { if err := localImage.Tag(tag); err != nil { diff --git a/vendor/github.com/containers/common/libimage/copier.go b/vendor/github.com/containers/common/libimage/copier.go index 23c781aaf3a..78e41406258 100644 --- a/vendor/github.com/containers/common/libimage/copier.go +++ b/vendor/github.com/containers/common/libimage/copier.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/containers/common/pkg/config" "github.com/containers/common/pkg/retry" "github.com/containers/image/v5/copy" "github.com/containers/image/v5/docker/reference" @@ -47,6 +48,8 @@ type CopyOptions struct { BlobInfoCacheDirPath string // Path to the certificates directory. CertDirPath string + // Force layer compression when copying to a `dir` transport destination. + DirForceCompress bool // Allow contacting registries over HTTP, or HTTPS with failed TLS // verification. Note that this does not affect other TLS connections. InsecureSkipTLSVerify types.OptionalBool @@ -114,6 +117,9 @@ type CopyOptions struct { // "username[:password]". Cannot be used in combination with // Username/Password. Credentials string + // IdentityToken is used to authenticate the user and get + // an access token for the registry. + IdentityToken string `json:"identitytoken,omitempty"` // ----- internal ----------------------------------------------------- @@ -145,30 +151,33 @@ var ( // getDockerAuthConfig extracts a docker auth config from the CopyOptions. Returns // nil if no credentials are set. func (options *CopyOptions) getDockerAuthConfig() (*types.DockerAuthConfig, error) { + authConf := &types.DockerAuthConfig{IdentityToken: options.IdentityToken} + if options.Username != "" { if options.Credentials != "" { return nil, errors.New("username/password cannot be used with credentials") } - return &types.DockerAuthConfig{ - Username: options.Username, - Password: options.Password, - }, nil + authConf.Username = options.Username + authConf.Password = options.Password + return authConf, nil } if options.Credentials != "" { - var username, password string split := strings.SplitN(options.Credentials, ":", 2) switch len(split) { case 1: - username = split[0] + authConf.Username = split[0] default: - username = split[0] - password = split[1] + authConf.Username = split[0] + authConf.Password = split[1] } - return &types.DockerAuthConfig{ - Username: username, - Password: password, - }, nil + return authConf, nil + } + + // We should return nil unless a token was set. That's especially + // useful for Podman's remote API. + if options.IdentityToken != "" { + return authConf, nil } return nil, nil @@ -193,6 +202,14 @@ func newCopier(sys *types.SystemContext, options *CopyOptions) (*copier, error) c.systemContext = &types.SystemContext{} } + if options.InsecureSkipTLSVerify != types.OptionalBoolUndefined { + c.systemContext.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify + c.systemContext.OCIInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue + c.systemContext.DockerDaemonInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue + } + + c.systemContext.DirForceCompress = options.DirForceCompress + if options.AuthFilePath != "" { c.systemContext.AuthFilePath = options.AuthFilePath } @@ -225,6 +242,10 @@ func newCopier(sys *types.SystemContext, options *CopyOptions) (*copier, error) c.systemContext.BlobInfoCacheDir = options.BlobInfoCacheDirPath } + if options.CertDirPath != "" { + c.systemContext.DockerCertPath = options.CertDirPath + } + policy, err := signature.DefaultPolicy(sys) if err != nil { return nil, err @@ -267,6 +288,13 @@ func newCopier(sys *types.SystemContext, options *CopyOptions) (*copier, error) c.imageCopyOptions.SignBy = options.SignBy c.imageCopyOptions.ReportWriter = options.Writer + defaultContainerConfig, err := config.Default() + if err != nil { + logrus.Warnf("failed to get container config for copy options: %v", err) + } else { + c.imageCopyOptions.MaxParallelDownloads = defaultContainerConfig.Engine.ImageParallelCopies + } + return &c, nil } diff --git a/vendor/github.com/containers/common/libimage/disk_usage.go b/vendor/github.com/containers/common/libimage/disk_usage.go new file mode 100644 index 00000000000..edfd095a015 --- /dev/null +++ b/vendor/github.com/containers/common/libimage/disk_usage.go @@ -0,0 +1,126 @@ +package libimage + +import ( + "context" + "time" +) + +// ImageDiskUsage reports the total size of an image. That is the size +type ImageDiskUsage struct { + // Number of containers using the image. + Containers int + // ID of the image. + ID string + // Repository of the image. + Repository string + // Tag of the image. + Tag string + // Created time stamp. + Created time.Time + // The amount of space that an image shares with another one (i.e. their common data). + SharedSize int64 + // The the amount of space that is only used by a given image. + UniqueSize int64 + // Sum of shared an unique size. + Size int64 +} + +// DiskUsage calculates the disk usage for each image in the local containers +// storage. Note that a single image may yield multiple usage reports, one for +// each repository tag. +func (r *Runtime) DiskUsage(ctx context.Context) ([]ImageDiskUsage, error) { + layerTree, err := r.layerTree() + if err != nil { + return nil, err + } + + images, err := r.ListImages(ctx, nil, nil) + if err != nil { + return nil, err + } + + var allUsages []ImageDiskUsage + for _, image := range images { + usages, err := diskUsageForImage(ctx, image, layerTree) + if err != nil { + return nil, err + } + allUsages = append(allUsages, usages...) + } + return allUsages, err +} + +// diskUsageForImage returns the disk-usage baseistics for the specified image. +func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) ([]ImageDiskUsage, error) { + base := ImageDiskUsage{ + ID: image.ID(), + Created: image.Created(), + Repository: "", + Tag: "", + } + + // Shared, unique and total size. + parent, err := tree.parent(ctx, image) + if err != nil { + return nil, err + } + childIDs, err := tree.children(ctx, image, false) + if err != nil { + return nil, err + } + + // Optimistically set unique size to the full size of the image. + size, err := image.Size() + if err != nil { + return nil, err + } + base.UniqueSize = size + + if len(childIDs) > 0 { + // If we have children, we share everything. + base.SharedSize = base.UniqueSize + base.UniqueSize = 0 + } else if parent != nil { + // If we have no children but a parent, remove the parent + // (shared) size from the unique one. + size, err := parent.Size() + if err != nil { + return nil, err + } + base.UniqueSize -= size + base.SharedSize = size + } + + base.Size = base.SharedSize + base.UniqueSize + + // Number of containers using the image. + containers, err := image.Containers() + if err != nil { + return nil, err + } + base.Containers = len(containers) + + repoTags, err := image.NamedRepoTags() + if err != nil { + return nil, err + } + + if len(repoTags) == 0 { + return []ImageDiskUsage{base}, nil + } + + pairs, err := ToNameTagPairs(repoTags) + if err != nil { + return nil, err + } + + results := make([]ImageDiskUsage, len(pairs)) + for i, pair := range pairs { + res := base + res.Repository = pair.Name + res.Tag = pair.Tag + results[i] = res + } + + return results, nil +} diff --git a/vendor/github.com/containers/common/libimage/filters.go b/vendor/github.com/containers/common/libimage/filters.go index 34df7626fd5..eae18fd9c77 100644 --- a/vendor/github.com/containers/common/libimage/filters.go +++ b/vendor/github.com/containers/common/libimage/filters.go @@ -9,6 +9,7 @@ import ( "time" filtersPkg "github.com/containers/common/pkg/filters" + "github.com/containers/common/pkg/timetype" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -45,15 +46,12 @@ func filterImages(images []*Image, filters []filterFunc) ([]*Image, error) { // compileImageFilters creates `filterFunc`s for the specified filters. The // required format is `key=value` with the following supported keys: -// after, since, before, dangling, id, label, readonly, reference, intermediate +// after, since, before, containers, dangling, id, label, readonly, reference, intermediate func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([]filterFunc, error) { logrus.Tracef("Parsing image filters %s", filters) filterFuncs := []filterFunc{} - visitedKeys := make(map[string]bool) - for _, filter := range filters { - // First, parse the filter. var key, value string split := strings.SplitN(filter, "=", 2) if len(split) != 2 { @@ -62,13 +60,6 @@ func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([] key = split[0] value = split[1] - - if _, exists := visitedKeys[key]; exists { - return nil, errors.Errorf("image filter %q specified multiple times", key) - } - visitedKeys[key] = true - - // Second, dispatch the filters. switch key { case "after", "since": @@ -85,6 +76,13 @@ func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([] } filterFuncs = append(filterFuncs, filterBefore(img.Created())) + case "containers": + containers, err := strconv.ParseBool(value) + if err != nil { + return nil, errors.Wrapf(err, "non-boolean value %q for dangling filter", value) + } + filterFuncs = append(filterFuncs, filterContainers(containers)) + case "dangling": dangling, err := strconv.ParseBool(value) if err != nil { @@ -115,6 +113,18 @@ func (r *Runtime) compileImageFilters(ctx context.Context, filters []string) ([] case "reference": filterFuncs = append(filterFuncs, filterReference(value)) + case "until": + ts, err := timetype.GetTimestamp(value, time.Now()) + if err != nil { + return nil, err + } + seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0) + if err != nil { + return nil, err + } + until := time.Unix(seconds, nanoseconds) + filterFuncs = append(filterFuncs, filterBefore(until)) + default: return nil, errors.Errorf("unsupported image filter %q", key) } @@ -179,6 +189,17 @@ func filterReadOnly(value bool) filterFunc { } } +// filterContainers creates a container filter for matching the specified value. +func filterContainers(value bool) filterFunc { + return func(img *Image) (bool, error) { + ctrs, err := img.Containers() + if err != nil { + return false, err + } + return (len(ctrs) > 0) == value, nil + } +} + // filterDangling creates a dangling filter for matching the specified value. func filterDangling(value bool) filterFunc { return func(img *Image) (bool, error) { diff --git a/vendor/github.com/containers/common/libimage/history.go b/vendor/github.com/containers/common/libimage/history.go index b966eb57e47..b63fe696bc5 100644 --- a/vendor/github.com/containers/common/libimage/history.go +++ b/vendor/github.com/containers/common/libimage/history.go @@ -2,13 +2,23 @@ package libimage import ( "context" + "time" - libimageTypes "github.com/containers/common/libimage/types" "github.com/containers/storage" ) +// ImageHistory contains the history information of an image. +type ImageHistory struct { + ID string `json:"id"` + Created *time.Time `json:"created"` + CreatedBy string `json:"createdBy"` + Size int64 `json:"size"` + Comment string `json:"comment"` + Tags []string `json:"tags"` +} + // History computes the image history of the image including all of its parents. -func (i *Image) History(ctx context.Context) ([]libimageTypes.ImageHistory, error) { +func (i *Image) History(ctx context.Context) ([]ImageHistory, error) { ociImage, err := i.toOCI(ctx) if err != nil { return nil, err @@ -19,7 +29,7 @@ func (i *Image) History(ctx context.Context) ([]libimageTypes.ImageHistory, erro return nil, err } - var allHistory []libimageTypes.ImageHistory + var allHistory []ImageHistory var layer *storage.Layer if i.TopLayer() != "" { layer, err = i.runtime.store.Layer(i.TopLayer()) @@ -33,7 +43,7 @@ func (i *Image) History(ctx context.Context) ([]libimageTypes.ImageHistory, erro numHistories := len(ociImage.History) - 1 usedIDs := make(map[string]bool) // prevents assigning images IDs more than once for x := numHistories; x >= 0; x-- { - history := libimageTypes.ImageHistory{ + history := ImageHistory{ ID: "", // may be overridden below Created: ociImage.History[x].Created, CreatedBy: ociImage.History[x].CreatedBy, diff --git a/vendor/github.com/containers/common/libimage/image.go b/vendor/github.com/containers/common/libimage/image.go index d6756e6ee23..b34eb540b2e 100644 --- a/vendor/github.com/containers/common/libimage/image.go +++ b/vendor/github.com/containers/common/libimage/image.go @@ -4,9 +4,9 @@ import ( "context" "path/filepath" "sort" + "strings" "time" - libimageTypes "github.com/containers/common/libimage/types" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/manifest" storageTransport "github.com/containers/image/v5/storage" @@ -40,7 +40,7 @@ type Image struct { // Inspect data we get from containers/image. partialInspectData *types.ImageInspectInfo // Fully assembled image data. - completeInspectData *libimageTypes.ImageData + completeInspectData *ImageData // Corresponding OCI image. ociv1Image *ociv1.Image } @@ -131,7 +131,7 @@ func (i *Image) Created() time.Time { func (i *Image) Labels(ctx context.Context) (map[string]string, error) { data, err := i.inspectInfo(ctx) if err != nil { - isManifestList, listErr := i.isManifestList(ctx) + isManifestList, listErr := i.IsManifestList(ctx) if listErr != nil { err = errors.Wrapf(err, "fallback error checking whether image is a manifest list: %v", err) } else if isManifestList { @@ -208,7 +208,9 @@ func (i *Image) removeContainers(fn RemoveContainerFunc) error { // Execute the custom removal func if specified. if fn != nil { logrus.Debugf("Removing containers of image %s with custom removal function", i.ID()) - return fn(i.ID()) + if err := fn(i.ID()); err != nil { + return err + } } containers, err := i.Containers() @@ -274,7 +276,10 @@ func (i *Image) Remove(ctx context.Context, options *RemoveImageOptions) error { // it recursively. parent, err := i.Parent(ctx) if err != nil { - return err + // See Podman commit fd9dd7065d44: we need to be tolerant + // toward corrupted images. + logrus.Warnf("error determining parent of image: %v, ignoring the error", err) + parent = nil } if _, err := i.runtime.store.DeleteImage(i.ID(), true); err != nil { @@ -282,7 +287,21 @@ func (i *Image) Remove(ctx context.Context, options *RemoveImageOptions) error { } delete(i.runtime.imageIDmap, i.ID()) - if parent == nil || !parent.IsDangling() { + if parent == nil { + return nil + } + + if !parent.IsDangling() { + return nil + } + hasChildren, err := parent.HasChildren(ctx) + if err != nil { + // See Podman commit fd9dd7065d44: we need to + // be tolerant toward corrupted images. + logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err) + hasChildren = false + } + if hasChildren { return nil } @@ -328,7 +347,7 @@ func (i *Image) Untag(name string) error { } if !removedName { - return nil + return errors.Errorf("%q: no such tag", name) } logrus.Debugf("Untagging %q from image %s", ref.String(), i.ID()) @@ -353,25 +372,78 @@ func (i *Image) RepoTags() ([]string, error) { return repoTags, nil } -// NammedTaggedRepoTags returns the repotags associated with the image as a +// NamedTaggedRepoTags returns the repotags associated with the image as a // slice of reference.NamedTagged. func (i *Image) NamedTaggedRepoTags() ([]reference.NamedTagged, error) { var repoTags []reference.NamedTagged for _, name := range i.Names() { - named, err := reference.ParseNormalizedNamed(name) + parsed, err := reference.Parse(name) + if err != nil { + return nil, err + } + named, isNamed := parsed.(reference.Named) + if !isNamed { + continue + } + tagged, isTagged := named.(reference.NamedTagged) + if !isTagged { + continue + } + repoTags = append(repoTags, tagged) + } + return repoTags, nil +} + +// NamedRepoTags returns the repotags associated with the image as a +// slice of reference.Named. +func (i *Image) NamedRepoTags() ([]reference.Named, error) { + var repoTags []reference.Named + for _, name := range i.Names() { + parsed, err := reference.Parse(name) if err != nil { return nil, err } - if tagged, isTagged := named.(reference.NamedTagged); isTagged { - repoTags = append(repoTags, tagged) + if named, isNamed := parsed.(reference.Named); isNamed { + repoTags = append(repoTags, named) } } return repoTags, nil } +// inRepoTags looks for the specified name/tag pair in the image's repo tags. +// Note that tag may be empty. +func (i *Image) inRepoTags(name, tag string) (reference.Named, error) { + repoTags, err := i.NamedRepoTags() + if err != nil { + return nil, err + } + + pairs, err := ToNameTagPairs(repoTags) + if err != nil { + return nil, err + } + + for _, pair := range pairs { + if tag != "" && tag != pair.Tag { + continue + } + if !strings.HasSuffix(pair.Name, name) { + continue + } + if len(pair.Name) == len(name) { // full match + return pair.named, nil + } + if pair.Name[len(pair.Name)-len(name)-1] == '/' { // matches at repo + return pair.named, nil + } + } + + return nil, nil +} + // RepoDigests returns a string array of repodigests associated with the image func (i *Image) RepoDigests() ([]string, error) { - var repoDigests []string + repoDigests := []string{} added := make(map[string]struct{}) for _, name := range i.Names() { @@ -416,6 +488,32 @@ func (i *Image) Mount(ctx context.Context, mountOptions []string, mountLabel str return mountPoint, nil } +// Mountpoint returns the path to image's mount point. The path is empty if +// the image is not mounted. +func (i *Image) Mountpoint() (string, error) { + mountedTimes, err := i.runtime.store.Mounted(i.TopLayer()) + if err != nil || mountedTimes == 0 { + if errors.Cause(err) == storage.ErrLayerUnknown { + // Can happen, Podman did it, but there's no + // explanation why. + err = nil + } + return "", err + } + + layer, err := i.runtime.store.Layer(i.TopLayer()) + if err != nil { + return "", err + } + + mountPoint, err := filepath.EvalSymlinks(layer.MountPoint) + if err != nil { + return "", err + } + + return mountPoint, nil +} + // Unmount the image. Use force to ignore the reference counter and forcefully // unmount. func (i *Image) Unmount(force bool) error { @@ -490,7 +588,7 @@ func (i *Image) HasDifferentDigest(ctx context.Context, remoteRef types.ImageRef } // driverData gets the driver data from the store on a layer -func (i *Image) driverData() (*libimageTypes.DriverData, error) { +func (i *Image) driverData() (*DriverData, error) { store := i.runtime.store layerID := i.TopLayer() driver, err := store.GraphDriver() @@ -504,7 +602,7 @@ func (i *Image) driverData() (*libimageTypes.DriverData, error) { if mountTimes, err := store.Mounted(layerID); mountTimes == 0 || err != nil { delete(metaData, "MergedDir") } - return &libimageTypes.DriverData{ + return &DriverData{ Name: driver.String(), Data: metaData, }, nil @@ -524,27 +622,6 @@ func (i *Image) StorageReference() (types.ImageReference, error) { return ref, nil } -// isManifestList returns true if the image is a manifest list (Docker) or an -// image index (OCI). This information may be useful to make certain execution -// paths more robust. -// NOTE: please use this function only to optimize specific execution paths. -// In general, errors should only be suppressed when necessary. -func (i *Image) isManifestList(ctx context.Context) (bool, error) { - ref, err := i.StorageReference() - if err != nil { - return false, err - } - imgRef, err := ref.NewImageSource(ctx, &i.runtime.systemContext) - if err != nil { - return false, err - } - _, manifestType, err := imgRef.GetManifest(ctx, nil) - if err != nil { - return false, err - } - return manifest.MIMETypeIsMultiImage(manifestType), nil -} - // source returns the possibly cached image reference. func (i *Image) source(ctx context.Context) (types.ImageSource, error) { if i.cached.imageSource != nil { @@ -562,6 +639,32 @@ func (i *Image) source(ctx context.Context) (types.ImageSource, error) { return src, nil } +// rawConfigBlob returns the image's config as a raw byte slice. Users need to +// unmarshal it to the corresponding type (OCI, Docker v2s{1,2}) +func (i *Image) rawConfigBlob(ctx context.Context) ([]byte, error) { + ref, err := i.StorageReference() + if err != nil { + return nil, err + } + + imageCloser, err := ref.NewImage(ctx, &i.runtime.systemContext) + if err != nil { + return nil, err + } + defer imageCloser.Close() + + return imageCloser.ConfigBlob(ctx) +} + +// Manifest returns the raw data and the MIME type of the image's manifest. +func (i *Image) Manifest(ctx context.Context) (rawManifest []byte, mimeType string, err error) { + src, err := i.source(ctx) + if err != nil { + return nil, "", err + } + return src.GetManifest(ctx, nil) +} + // getImageDigest creates an image object and uses the hex value of the digest as the image ID // for parsing the store reference func getImageDigest(ctx context.Context, src types.ImageReference, sys *types.SystemContext) (string, error) { diff --git a/vendor/github.com/containers/common/libimage/image_tree.go b/vendor/github.com/containers/common/libimage/image_tree.go index 5ab1808363c..6583a700739 100644 --- a/vendor/github.com/containers/common/libimage/image_tree.go +++ b/vendor/github.com/containers/common/libimage/image_tree.go @@ -4,19 +4,14 @@ import ( "fmt" "strings" + "github.com/disiqueira/gotree/v3" "github.com/docker/go-units" ) -const ( - imageTreeMiddleItem = "├── " - imageTreeContinueItem = "│ " - imageTreeLastItem = "└── " -) - // Tree generates a tree for the specified image and its layers. Use // `traverseChildren` to traverse the layers of all children. By default, only // layers of the image are printed. -func (i *Image) Tree(traverseChildren bool) (*strings.Builder, error) { +func (i *Image) Tree(traverseChildren bool) (string, error) { // NOTE: a string builder prevents us from copying to much data around // and compile the string when and where needed. sb := &strings.Builder{} @@ -24,85 +19,78 @@ func (i *Image) Tree(traverseChildren bool) (*strings.Builder, error) { // First print the pretty header for the target image. size, err := i.Size() if err != nil { - return nil, err + return "", err } repoTags, err := i.RepoTags() if err != nil { - return nil, err + return "", err } fmt.Fprintf(sb, "Image ID: %s\n", i.ID()[:12]) fmt.Fprintf(sb, "Tags: %s\n", repoTags) fmt.Fprintf(sb, "Size: %v\n", units.HumanSizeWithPrecision(float64(size), 4)) if i.TopLayer() != "" { - fmt.Fprintf(sb, "Image Layers\n") + fmt.Fprintf(sb, "Image Layers") } else { - fmt.Fprintf(sb, "No Image Layers\n") + fmt.Fprintf(sb, "No Image Layers") } + tree := gotree.New(sb.String()) + layerTree, err := i.runtime.layerTree() if err != nil { - return nil, err + return "", err } imageNode := layerTree.node(i.TopLayer()) + // Traverse the entire tree down to all children. if traverseChildren { - return imageTreeTraverseChildren(sb, imageNode, "", true) - } - - // Walk all layers of the image and assemlbe their data. - for parentNode := imageNode.parent; parentNode != nil; parentNode = parentNode.parent { - indent := imageTreeMiddleItem - if parentNode.parent == nil { - indent = imageTreeLastItem - } - - var tags string - repoTags, err := parentNode.repoTags() - if err != nil { - return nil, err + if err := imageTreeTraverseChildren(imageNode, tree); err != nil { + return "", err } - if len(repoTags) > 0 { - tags = fmt.Sprintf(" Top Layer of: %s", repoTags) + } else { + // Walk all layers of the image and assemlbe their data. + for parentNode := imageNode; parentNode != nil; parentNode = parentNode.parent { + if parentNode.layer == nil { + break // we're done + } + var tags string + repoTags, err := parentNode.repoTags() + if err != nil { + return "", err + } + if len(repoTags) > 0 { + tags = fmt.Sprintf(" Top Layer of: %s", repoTags) + } + tree.Add(fmt.Sprintf("ID: %s Size: %7v%s", parentNode.layer.ID[:12], units.HumanSizeWithPrecision(float64(parentNode.layer.UncompressedSize), 4), tags)) } - fmt.Fprintf(sb, "%s ID: %s Size: %7v%s\n", indent, parentNode.layer.ID[:12], units.HumanSizeWithPrecision(float64(parentNode.layer.UncompressedSize), 4), tags) } - return sb, nil + return tree.Print(), nil } -func imageTreeTraverseChildren(sb *strings.Builder, node *layerNode, prefix string, last bool) (*strings.Builder, error) { - numChildren := len(node.children) - if numChildren == 0 { - return sb, nil +func imageTreeTraverseChildren(node *layerNode, parent gotree.Tree) error { + var tags string + repoTags, err := node.repoTags() + if err != nil { + return err } - sb.WriteString(prefix) - - intend := imageTreeMiddleItem - if !last { - prefix += imageTreeContinueItem - } else { - intend = imageTreeLastItem - prefix += " " + if len(repoTags) > 0 { + tags = fmt.Sprintf(" Top Layer of: %s", repoTags) } + newNode := parent.Add(fmt.Sprintf("ID: %s Size: %7v%s", node.layer.ID[:12], units.HumanSizeWithPrecision(float64(node.layer.UncompressedSize), 4), tags)) + + if len(node.children) <= 1 { + newNode = parent + } for i := range node.children { child := node.children[i] - var tags string - repoTags, err := child.repoTags() - if err != nil { - return nil, err - } - if len(repoTags) > 0 { - tags = fmt.Sprintf(" Top Layer of: %s", repoTags) - } - fmt.Fprintf(sb, "%sID: %s Size: %7v%s\n", intend, child.layer.ID[:12], units.HumanSizeWithPrecision(float64(child.layer.UncompressedSize), 4), tags) - sb, err = imageTreeTraverseChildren(sb, child, prefix, i == numChildren-1) - if err != nil { - return nil, err + if err := imageTreeTraverseChildren(child, newNode); err != nil { + return err } } - return sb, nil + return nil } diff --git a/vendor/github.com/containers/common/libimage/import.go b/vendor/github.com/containers/common/libimage/import.go index 31dc4a0fa90..845c886662b 100644 --- a/vendor/github.com/containers/common/libimage/import.go +++ b/vendor/github.com/containers/common/libimage/import.go @@ -86,6 +86,7 @@ func (r *Runtime) Import(ctx context.Context, path string, options *ImportOption if err != nil { return "", err } + name = "sha256:" + name[1:] // strip leading "@" } destRef, err := storageTransport.Transport.ParseStoreReference(r.store, name) diff --git a/vendor/github.com/containers/common/libimage/inspect.go b/vendor/github.com/containers/common/libimage/inspect.go index ebcb7ccd0d1..685789bb8a9 100644 --- a/vendor/github.com/containers/common/libimage/inspect.go +++ b/vendor/github.com/containers/common/libimage/inspect.go @@ -3,20 +3,67 @@ package libimage import ( "context" "encoding/json" + "time" - libimageTypes "github.com/containers/common/libimage/types" "github.com/containers/image/v5/manifest" "github.com/containers/image/v5/types" + "github.com/opencontainers/go-digest" ociv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" ) +// ImageData contains the inspected data of an image. +type ImageData struct { + ID string `json:"Id"` + Digest digest.Digest `json:"Digest"` + RepoTags []string `json:"RepoTags"` + RepoDigests []string `json:"RepoDigests"` + Parent string `json:"Parent"` + Comment string `json:"Comment"` + Created *time.Time `json:"Created"` + Config *ociv1.ImageConfig `json:"Config"` + Version string `json:"Version"` + Author string `json:"Author"` + Architecture string `json:"Architecture"` + Os string `json:"Os"` + Size int64 `json:"Size"` + VirtualSize int64 `json:"VirtualSize"` + GraphDriver *DriverData `json:"GraphDriver"` + RootFS *RootFS `json:"RootFS"` + Labels map[string]string `json:"Labels"` + Annotations map[string]string `json:"Annotations"` + ManifestType string `json:"ManifestType"` + User string `json:"User"` + History []ociv1.History `json:"History"` + NamesHistory []string `json:"NamesHistory"` + HealthCheck *manifest.Schema2HealthConfig `json:"Healthcheck,omitempty"` +} + +// DriverData includes data on the storage driver of the image. +type DriverData struct { + Name string `json:"Name"` + Data map[string]string `json:"Data"` +} + +// RootFS includes data on the root filesystem of the image. +type RootFS struct { + Type string `json:"Type"` + Layers []digest.Digest `json:"Layers"` +} + // Inspect inspects the image. Use `withSize` to also perform the // comparatively expensive size computation of the image. -func (i *Image) Inspect(ctx context.Context, withSize bool) (*libimageTypes.ImageData, error) { +func (i *Image) Inspect(ctx context.Context, withSize bool) (*ImageData, error) { logrus.Debugf("Inspecting image %s", i.ID()) if i.cached.completeInspectData != nil { + if withSize && i.cached.completeInspectData.Size == int64(-1) { + size, err := i.Size() + if err != nil { + return nil, err + } + i.cached.completeInspectData.Size = size + } return i.cached.completeInspectData, nil } @@ -54,7 +101,7 @@ func (i *Image) Inspect(ctx context.Context, withSize bool) (*libimageTypes.Imag } } - data := &libimageTypes.ImageData{ + data := &ImageData{ ID: i.ID(), RepoTags: repoTags, RepoDigests: repoDigests, @@ -68,7 +115,7 @@ func (i *Image) Inspect(ctx context.Context, withSize bool) (*libimageTypes.Imag VirtualSize: size, // TODO: they should be different (inherited from Podman) Digest: i.Digest(), Labels: info.Labels, - RootFS: &libimageTypes.RootFS{ + RootFS: &RootFS{ Type: ociImage.RootFS.Type, Layers: ociImage.RootFS.DiffIDs, }, @@ -108,15 +155,24 @@ func (i *Image) Inspect(ctx context.Context, withSize bool) (*libimageTypes.Imag } // Docker image - case manifest.DockerV2Schema2MediaType: - var dockerManifest manifest.Schema2Image - if err := json.Unmarshal(manifestRaw, &dockerManifest); err != nil { + case manifest.DockerV2Schema1MediaType, manifest.DockerV2Schema2MediaType: + rawConfig, err := i.rawConfigBlob(ctx) + if err != nil { + return nil, err + } + var dockerManifest manifest.Schema2V1Image + if err := json.Unmarshal(rawConfig, &dockerManifest); err != nil { return nil, err } data.Comment = dockerManifest.Comment data.HealthCheck = dockerManifest.ContainerConfig.Healthcheck } + if data.Annotations == nil { + // Podman compat + data.Annotations = make(map[string]string) + } + i.cached.completeInspectData = data return data, nil diff --git a/vendor/github.com/containers/common/libimage/load.go b/vendor/github.com/containers/common/libimage/load.go index cfee2740c38..a95d0f5f537 100644 --- a/vendor/github.com/containers/common/libimage/load.go +++ b/vendor/github.com/containers/common/libimage/load.go @@ -3,11 +3,13 @@ package libimage import ( "context" "errors" + "os" dirTransport "github.com/containers/image/v5/directory" dockerArchiveTransport "github.com/containers/image/v5/docker/archive" ociArchiveTransport "github.com/containers/image/v5/oci/archive" ociTransport "github.com/containers/image/v5/oci/layout" + "github.com/containers/image/v5/types" "github.com/sirupsen/logrus" ) @@ -33,6 +35,7 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( for _, f := range []func() ([]string, error){ // OCI func() ([]string, error) { + logrus.Debugf("-> Attempting to load %q as an OCI directory", path) ref, err := ociTransport.NewReference(path, "") if err != nil { return nil, err @@ -42,6 +45,7 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( // OCI-ARCHIVE func() ([]string, error) { + logrus.Debugf("-> Attempting to load %q as an OCI archive", path) ref, err := ociArchiveTransport.NewReference(path, "") if err != nil { return nil, err @@ -51,6 +55,7 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( // DIR func() ([]string, error) { + logrus.Debugf("-> Attempting to load %q as a Docker dir", path) ref, err := dirTransport.NewReference(path) if err != nil { return nil, err @@ -60,11 +65,12 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( // DOCKER-ARCHIVE func() ([]string, error) { + logrus.Debugf("-> Attempting to load %q as a Docker archive", path) ref, err := dockerArchiveTransport.ParseReference(path) if err != nil { return nil, err } - return r.copyFromDockerArchive(ctx, ref, &options.CopyOptions) + return r.loadMultiImageDockerArchive(ctx, ref, &options.CopyOptions) }, // Give a decent error message if nothing above worked. @@ -81,3 +87,39 @@ func (r *Runtime) Load(ctx context.Context, path string, options *LoadOptions) ( return nil, loadError } + +// loadMultiImageDockerArchive loads the docker archive specified by ref. In +// case the path@reference notation was used, only the specifiec image will be +// loaded. Otherwise, all images will be loaded. +func (r *Runtime) loadMultiImageDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) { + // If we cannot stat the path, it either does not exist OR the correct + // syntax to reference an image within the archive was used, so we + // should. + path := ref.StringWithinTransport() + if _, err := os.Stat(path); err != nil { + return r.copyFromDockerArchive(ctx, ref, options) + } + + reader, err := dockerArchiveTransport.NewReader(&r.systemContext, path) + if err != nil { + return nil, err + } + + refLists, err := reader.List() + if err != nil { + return nil, err + } + + var copiedImages []string + for _, list := range refLists { + for _, listRef := range list { + names, err := r.copyFromDockerArchiveReaderReference(ctx, reader, listRef, options) + if err != nil { + return nil, err + } + copiedImages = append(copiedImages, names...) + } + } + + return copiedImages, nil +} diff --git a/vendor/github.com/containers/common/libimage/manifest_list.go b/vendor/github.com/containers/common/libimage/manifest_list.go new file mode 100644 index 00000000000..592066895f8 --- /dev/null +++ b/vendor/github.com/containers/common/libimage/manifest_list.go @@ -0,0 +1,380 @@ +package libimage + +import ( + "context" + "fmt" + + "github.com/containers/common/libimage/manifests" + imageCopy "github.com/containers/image/v5/copy" + "github.com/containers/image/v5/docker" + "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/transports/alltransports" + "github.com/containers/image/v5/types" + "github.com/opencontainers/go-digest" + "github.com/pkg/errors" +) + +// NOTE: the abstractions and APIs here are a first step to further merge +// `libimage/manifests` into `libimage`. + +// ManifestList represents a manifest list (Docker) or an image index (OCI) in +// the local containers storage. +type ManifestList struct { + // NOTE: the *List* suffix is intentional as the term "manifest" is + // used ambiguously across the ecosystem. It may refer to the (JSON) + // manifest of an ordinary image OR to a manifest *list* (Docker) or to + // image index (OCI). + // It's a bit more work when typing but without ambiguity. + + // The underlying image in the containers storage. + image *Image + + // The underlying manifest list. + list manifests.List +} + +// ID returns the ID of the manifest list. +func (m *ManifestList) ID() string { + return m.image.ID() +} + +// CreateManifestList creates a new empty manifest list with the specified +// name. +func (r *Runtime) CreateManifestList(name string) (*ManifestList, error) { + normalized, err := NormalizeName(name) + if err != nil { + return nil, err + } + + list := manifests.Create() + listID, err := list.SaveToImage(r.store, "", []string{normalized.String()}, manifest.DockerV2ListMediaType) + if err != nil { + return nil, err + } + + mList, err := r.LookupManifestList(listID) + if err != nil { + return nil, err + } + + return mList, nil +} + +// LookupManifestList looks up a manifest list with the specified name in the +// containers storage. +func (r *Runtime) LookupManifestList(name string) (*ManifestList, error) { + image, list, err := r.lookupManifestList(name) + if err != nil { + return nil, err + } + return &ManifestList{image: image, list: list}, nil +} + +func (r *Runtime) lookupManifestList(name string) (*Image, manifests.List, error) { + image, _, err := r.LookupImage(name, &LookupImageOptions{IgnorePlatform: true}) + if err != nil { + return nil, nil, err + } + list, err := image.getManifestList() + if err != nil { + return nil, nil, err + } + return image, list, nil +} + +// ToManifestList converts the image into a manifest list. An error is thrown +// if the image is no manifest list. +func (i *Image) ToManifestList() (*ManifestList, error) { + list, err := i.getManifestList() + if err != nil { + return nil, err + } + return &ManifestList{image: i, list: list}, nil +} + +// LookupInstance looks up an instance of the manifest list matching the +// specified platform. The local machine's platform is used if left empty. +func (m *ManifestList) LookupInstance(ctx context.Context, architecture, os, variant string) (*Image, error) { + sys := m.image.runtime.systemContext + if architecture != "" { + sys.ArchitectureChoice = architecture + } + if os != "" { + sys.OSChoice = os + } + if architecture != "" { + sys.VariantChoice = variant + } + + // Now look at the *manifest* and select a matching instance. + rawManifest, manifestType, err := m.image.Manifest(ctx) + if err != nil { + return nil, err + } + list, err := manifest.ListFromBlob(rawManifest, manifestType) + if err != nil { + return nil, err + } + instanceDigest, err := list.ChooseInstance(&sys) + if err != nil { + return nil, err + } + + allImages, err := m.image.runtime.ListImages(ctx, nil, nil) + if err != nil { + return nil, err + } + + for _, image := range allImages { + for _, imageDigest := range image.Digests() { + if imageDigest == instanceDigest { + return image, nil + } + } + } + + return nil, errors.Errorf("could not find an instance in manifest list %s", m.ID()) +} + +// Saves the specified manifest list and reloads it from storage with the new ID. +func (m *ManifestList) saveAndReload() error { + newID, err := m.list.SaveToImage(m.image.runtime.store, m.image.ID(), nil, "") + if err != nil { + return err + } + image, list, err := m.image.runtime.lookupManifestList(newID) + if err != nil { + return err + } + m.image = image + m.list = list + return nil +} + +// getManifestList is a helper to obtain a manifest list +func (i *Image) getManifestList() (manifests.List, error) { + _, list, err := manifests.LoadFromImage(i.runtime.store, i.ID()) + return list, err +} + +// IsManifestList returns true if the image is a manifest list (Docker) or an +// image index (OCI). This information may be critical to make certain +// execution paths more robust (e.g., suppress certain errors). +func (i *Image) IsManifestList(ctx context.Context) (bool, error) { + ref, err := i.StorageReference() + if err != nil { + return false, err + } + imgRef, err := ref.NewImageSource(ctx, &i.runtime.systemContext) + if err != nil { + return false, err + } + _, manifestType, err := imgRef.GetManifest(ctx, nil) + if err != nil { + return false, err + } + return manifest.MIMETypeIsMultiImage(manifestType), nil +} + +// Inspect returns a dockerized version of the manifest list. +func (m *ManifestList) Inspect() (*manifest.Schema2List, error) { + return m.list.Docker(), nil +} + +// Options for adding a manifest list. +type ManifestListAddOptions struct { + // Add all images to the list if the to-be-added image itself is a + // manifest list. + All bool `json:"all"` + // containers-auth.json(5) file to use when authenticating against + // container registries. + AuthFilePath string + // Path to the certificates directory. + CertDirPath string + // Allow contacting registries over HTTP, or HTTPS with failed TLS + // verification. Note that this does not affect other TLS connections. + InsecureSkipTLSVerify types.OptionalBool + // Username to use when authenticating at a container registry. + Username string + // Password to use when authenticating at a container registry. + Password string +} + +// Add adds one or more manifests to the manifest list and returns the digest +// of the added instance. +func (m *ManifestList) Add(ctx context.Context, name string, options *ManifestListAddOptions) (digest.Digest, error) { + if options == nil { + options = &ManifestListAddOptions{} + } + + ref, err := alltransports.ParseImageName(name) + if err != nil { + withDocker := fmt.Sprintf("%s://%s", docker.Transport.Name(), name) + ref, err = alltransports.ParseImageName(withDocker) + if err != nil { + return "", err + } + } + + // Now massage in the copy-related options into the system context. + systemContext := m.image.runtime.systemContext + if options.AuthFilePath != "" { + systemContext.AuthFilePath = options.AuthFilePath + } + if options.CertDirPath != "" { + systemContext.DockerCertPath = options.CertDirPath + } + if options.InsecureSkipTLSVerify != types.OptionalBoolUndefined { + systemContext.DockerInsecureSkipTLSVerify = options.InsecureSkipTLSVerify + systemContext.OCIInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue + systemContext.DockerDaemonInsecureSkipTLSVerify = options.InsecureSkipTLSVerify == types.OptionalBoolTrue + } + if options.Username != "" { + systemContext.DockerAuthConfig = &types.DockerAuthConfig{ + Username: options.Username, + Password: options.Password, + } + } + + newDigest, err := m.list.Add(ctx, &systemContext, ref, options.All) + if err != nil { + return "", err + } + + // Write the changes to disk. + if err := m.saveAndReload(); err != nil { + return "", err + } + return newDigest, nil +} + +// Options for annotationg a manifest list. +type ManifestListAnnotateOptions struct { + // Add the specified annotations to the added image. + Annotations map[string]string + // Add the specified architecture to the added image. + Architecture string + // Add the specified features to the added image. + Features []string + // Add the specified OS to the added image. + OS string + // Add the specified OS features to the added image. + OSFeatures []string + // Add the specified OS version to the added image. + OSVersion string + // Add the specified variant to the added image. + Variant string +} + +// Annotate an image instance specified by `d` in the manifest list. +func (m *ManifestList) AnnotateInstance(d digest.Digest, options *ManifestListAnnotateOptions) error { + if options == nil { + return nil + } + + if len(options.OS) > 0 { + if err := m.list.SetOS(d, options.OS); err != nil { + return err + } + } + if len(options.OSVersion) > 0 { + if err := m.list.SetOSVersion(d, options.OSVersion); err != nil { + return err + } + } + if len(options.Features) > 0 { + if err := m.list.SetFeatures(d, options.Features); err != nil { + return err + } + } + if len(options.OSFeatures) > 0 { + if err := m.list.SetOSFeatures(d, options.OSFeatures); err != nil { + return err + } + } + if len(options.Architecture) > 0 { + if err := m.list.SetArchitecture(d, options.Architecture); err != nil { + return err + } + } + if len(options.Variant) > 0 { + if err := m.list.SetVariant(d, options.Variant); err != nil { + return err + } + } + if len(options.Annotations) > 0 { + if err := m.list.SetAnnotations(&d, options.Annotations); err != nil { + return err + } + } + + // Write the changes to disk. + if err := m.saveAndReload(); err != nil { + return err + } + return nil +} + +// RemoveInstance removes the instance specified by `d` from the manifest list. +// Returns the new ID of the image. +func (m *ManifestList) RemoveInstance(d digest.Digest) error { + if err := m.list.Remove(d); err != nil { + return err + } + + // Write the changes to disk. + if err := m.saveAndReload(); err != nil { + return err + } + return nil +} + +// ManifestListPushOptions allow for customizing pushing a manifest list. +type ManifestListPushOptions struct { + CopyOptions + + // For tweaking the list selection. + ImageListSelection imageCopy.ImageListSelection + // Use when selecting only specific imags. + Instances []digest.Digest +} + +// Push pushes a manifest to the specified destination. +func (m *ManifestList) Push(ctx context.Context, destination string, options *ManifestListPushOptions) (digest.Digest, error) { + if options == nil { + options = &ManifestListPushOptions{} + } + + dest, err := alltransports.ParseImageName(destination) + if err != nil { + oldErr := err + dest, err = alltransports.ParseImageName("docker://" + destination) + if err != nil { + return "", oldErr + } + } + + // NOTE: we're using the logic in copier to create a proper + // types.SystemContext. This prevents us from having an error prone + // code duplicate here. + sys := m.image.runtime.systemContext + copier, err := newCopier(&sys, &options.CopyOptions) + if err != nil { + return "", err + } + defer copier.close() + + pushOptions := manifests.PushOptions{ + Store: m.image.runtime.store, + SystemContext: copier.systemContext, + ImageListSelection: options.ImageListSelection, + Instances: options.Instances, + ReportWriter: options.Writer, + SignBy: options.SignBy, + RemoveSignatures: options.RemoveSignatures, + ManifestType: options.ManifestMIMEType, + } + + _, d, err := m.list.Push(ctx, dest, pushOptions) + return d, err +} diff --git a/vendor/github.com/containers/common/libimage/normalize.go b/vendor/github.com/containers/common/libimage/normalize.go index 5ba94fd4895..de77d21fb73 100644 --- a/vendor/github.com/containers/common/libimage/normalize.go +++ b/vendor/github.com/containers/common/libimage/normalize.go @@ -61,16 +61,24 @@ type NameTagPair struct { Name string // Tag of the RepoTag. Maybe "". Tag string + + // for internal use + named reference.Named } // ToNameTagsPairs splits repoTags into name&tag pairs. // Guaranteed to return at least one pair. -func ToNameTagPairs(repoTags []reference.NamedTagged) ([]NameTagPair, error) { +func ToNameTagPairs(repoTags []reference.Named) ([]NameTagPair, error) { none := "" var pairs []NameTagPair - for _, named := range repoTags { - pair := NameTagPair{Name: named.Name(), Tag: none} + for i, named := range repoTags { + pair := NameTagPair{ + Name: named.Name(), + Tag: none, + named: repoTags[i], + } + if tagged, isTagged := named.(reference.NamedTagged); isTagged { pair.Tag = tagged.Tag() } diff --git a/vendor/github.com/containers/common/libimage/pull.go b/vendor/github.com/containers/common/libimage/pull.go index e38565d4771..10380b78826 100644 --- a/vendor/github.com/containers/common/libimage/pull.go +++ b/vendor/github.com/containers/common/libimage/pull.go @@ -6,7 +6,7 @@ import ( "io" "strings" - libimageTypes "github.com/containers/common/libimage/types" + "github.com/containers/common/pkg/config" dirTransport "github.com/containers/image/v5/directory" dockerTransport "github.com/containers/image/v5/docker" dockerArchiveTransport "github.com/containers/image/v5/docker/archive" @@ -36,7 +36,7 @@ type PullOptions struct { // name will be treated as a reference to a registry (i.e., docker transport). // // Note that pullPolicy is only used when pulling from a container registry but -// it *must* be different than the default value `PullPolicyUnsupported`. This +// it *must* be different than the default value `config.PullPolicyUnsupported`. This // way, callers are forced to decide on the pull behaviour. The reasoning // behind is that some (commands of some) tools have different default pull // policies (e.g., buildah-bud versus podman-build). Making the pull-policy @@ -45,7 +45,7 @@ type PullOptions struct { // The errror is storage.ErrImageUnknown iff the pull policy is set to "never" // and no local image has been found. This allows for an easier integration // into some users of this package (e.g., Buildah). -func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy libimageTypes.PullPolicy, options *PullOptions) ([]*Image, error) { +func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullPolicy, options *PullOptions) ([]*Image, error) { logrus.Debugf("Pulling image %s", name) if options == nil { @@ -57,16 +57,13 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy libimageType // If the image clearly refers to a local one, we can look it up directly. // In fact, we need to since they are not parseable. if strings.HasPrefix(name, "sha256:") || (len(name) == 64 && !strings.Contains(name, "/.:@")) { - if pullPolicy == libimageTypes.PullPolicyAlways { + if pullPolicy == config.PullPolicyAlways { return nil, errors.Errorf("pull policy is always but image has been referred to by ID (%s)", name) } local, _, err := r.LookupImage(name, nil) if err != nil { return nil, err } - if local == nil { - return nil, errors.Wrap(storage.ErrImageUnknown, name) - } return []*Image{local}, err } @@ -126,9 +123,6 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy libimageType if err != nil { return nil, errors.Wrapf(err, "error locating pulled image %q name in containers storage", name) } - if local == nil { - return nil, errors.Wrap(storage.ErrImageUnknown, name) - } localImages = append(localImages, local) } @@ -228,21 +222,25 @@ func (r *Runtime) storageReferencesReferencesFromArchiveReader(ctx context.Conte return references, imageNames, nil } -// copyFromDockerArchive copies one or more images from the specified -// reference. +// copyFromDockerArchive copies one image from the specified reference. func (r *Runtime) copyFromDockerArchive(ctx context.Context, ref types.ImageReference, options *CopyOptions) ([]string, error) { - c, err := newCopier(&r.systemContext, options) + // There may be more than one image inside the docker archive, so we + // need a quick glimpse inside. + reader, readerRef, err := dockerArchiveTransport.NewReaderForReference(&r.systemContext, ref) if err != nil { return nil, err } - defer c.close() - // There may be more than one image inside the docker archive, so we - // need a quick glimpse inside. - reader, readerRef, err := dockerArchiveTransport.NewReaderForReference(&r.systemContext, ref) + return r.copyFromDockerArchiveReaderReference(ctx, reader, readerRef, options) +} + +// copyFromDockerArchiveReaderReference copies the specified readerRef from reader. +func (r *Runtime) copyFromDockerArchiveReaderReference(ctx context.Context, reader *dockerArchiveTransport.Reader, readerRef types.ImageReference, options *CopyOptions) ([]string, error) { + c, err := newCopier(&r.systemContext, options) if err != nil { return nil, err } + defer c.close() // Get a slice of storage references we can copy. references, destNames, err := r.storageReferencesReferencesFromArchiveReader(ctx, readerRef, reader) @@ -265,7 +263,7 @@ func (r *Runtime) copyFromDockerArchive(ctx context.Context, ref types.ImageRefe // can later be used to look up the image in the local containers storage. // // If options.All is set, all tags from the specified registry will be pulled. -func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference, inputName string, pullPolicy libimageTypes.PullPolicy, options *PullOptions) ([]string, error) { +func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference, inputName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) { // Sanity check. if err := pullPolicy.Validate(); err != nil { return nil, err @@ -283,6 +281,12 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference pulledTags := []string{} for _, tag := range tags { + select { // Let's be gentle with Podman remote. + case <-ctx.Done(): + return nil, errors.Errorf("pulling cancelled") + default: + // We can continue. + } tagged, err := reference.WithTag(named, tag) if err != nil { return nil, errors.Wrapf(err, "error creating tagged reference (name %s, tag %s)", named.String(), tag) @@ -301,7 +305,7 @@ func (r *Runtime) copyFromRegistry(ctx context.Context, ref types.ImageReference // from a registry. On successful pull it returns the used fully-qualified // name that can later be used to look up the image in the local containers // storage. -func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName string, pullPolicy libimageTypes.PullPolicy, options *PullOptions) ([]string, error) { +func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName string, pullPolicy config.PullPolicy, options *PullOptions) ([]string, error) { // Sanity check. if err := pullPolicy.Validate(); err != nil { return nil, err @@ -318,11 +322,11 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str // If there's already a local image "localhost/foo", then we should // attempt pulling that instead of doing the full short-name dance. localImage, resolvedImageName, err = r.LookupImage(imageName, nil) - if err != nil { + if err != nil && errors.Cause(err) != storage.ErrImageUnknown { return nil, errors.Wrap(err, "error looking up local image") } - if pullPolicy == libimageTypes.PullPolicyNever { + if pullPolicy == config.PullPolicyNever { if localImage != nil { logrus.Debugf("Pull policy %q but no local image has been found for %s", pullPolicy, imageName) return []string{resolvedImageName}, nil @@ -331,14 +335,14 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str return nil, errors.Wrap(storage.ErrImageUnknown, imageName) } - if pullPolicy == libimageTypes.PullPolicyMissing && localImage != nil { + if pullPolicy == config.PullPolicyMissing && localImage != nil { return []string{resolvedImageName}, nil } // If we looked up the image by ID, we cannot really pull from anywhere. if localImage != nil && strings.HasPrefix(localImage.ID(), imageName) { switch pullPolicy { - case libimageTypes.PullPolicyAlways: + case config.PullPolicyAlways: return nil, errors.Errorf("pull policy is always but image has been referred to by ID (%s)", imageName) default: return []string{resolvedImageName}, nil @@ -397,7 +401,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str return nil, err } - if pullPolicy == libimageTypes.PullPolicyNewer && localImage != nil { + if pullPolicy == config.PullPolicyNewer && localImage != nil { isNewer, err := localImage.HasDifferentDigest(ctx, srcRef) if err != nil { pullErrors = append(pullErrors, err) @@ -439,7 +443,7 @@ func (r *Runtime) copySingleImageFromRegistry(ctx context.Context, imageName str return []string{candidate.Value.String()}, nil } - if localImage != nil && pullPolicy == libimageTypes.PullPolicyNewer { + if localImage != nil && pullPolicy == config.PullPolicyNewer { return []string{resolvedImageName}, nil } diff --git a/vendor/github.com/containers/common/libimage/pull_policy.go b/vendor/github.com/containers/common/libimage/pull_policy.go deleted file mode 100644 index 45c25b1869e..00000000000 --- a/vendor/github.com/containers/common/libimage/pull_policy.go +++ /dev/null @@ -1,90 +0,0 @@ -package libimage - -import ( - "fmt" - - "github.com/pkg/errors" -) - -// PullPolicy determines how and which images are being pulled from a container -// registry (i.e., docker transport only). -// -// Supported string values are: -// * "always" <-> PullPolicyAlways -// * "missing" <-> PullPolicyMissing -// * "newer" <-> PullPolicyNewer -// * "never" <-> PullPolicyNever -type PullPolicy int - -const ( - // This default value forces callers to setup a custom default policy. - // Some tools use different policies (e.g., buildah-bud versus - // podman-build). - PullPolicyUnsupported PullPolicy = iota - // Always pull the image. - PullPolicyAlways - // Pull the image only if it could not be found in the local containers - // storage. - PullPolicyMissing - // Pull if the image on the registry is new than the one in the local - // containers storage. An image is considered to be newer when the - // digests are different. Comparing the time stamps is prone to - // errors. - PullPolicyNewer - // Never pull the image but use the one from the local containers - // storage. - PullPolicyNever -) - -// String converts a PullPolicy into a string. -// -// Supported string values are: -// * "always" <-> PullPolicyAlways -// * "missing" <-> PullPolicyMissing -// * "newer" <-> PullPolicyNewer -// * "never" <-> PullPolicyNever -func (p PullPolicy) String() string { - switch p { - case PullPolicyAlways: - return "always" - case PullPolicyMissing: - return "missing" - case PullPolicyNewer: - return "newer" - case PullPolicyNever: - return "never" - } - return fmt.Sprintf("unrecognized policy %d", p) -} - -// Validate returns if the pull policy is not supported. -func (p PullPolicy) Validate() error { - switch p { - case PullPolicyAlways, PullPolicyMissing, PullPolicyNewer, PullPolicyNever: - return nil - default: - return errors.Errorf("unsupported pull policy %d", p) - } -} - -// ParsePullPolicy parses the string into a pull policy. -// -// Supported string values are: -// * "always" <-> PullPolicyAlways -// * "missing" <-> PullPolicyMissing -// * "newer" <-> PullPolicyNewer -// * "never" <-> PullPolicyNever -func ParsePullPolicy(s string) (PullPolicy, error) { - switch s { - case "always": - return PullPolicyAlways, nil - case "missing": - return PullPolicyMissing, nil - case "newer": - return PullPolicyNewer, nil - case "never": - return PullPolicyMissing, nil - default: - return PullPolicyUnsupported, errors.Errorf("unsupported pull policy %q", s) - } -} diff --git a/vendor/github.com/containers/common/libimage/push.go b/vendor/github.com/containers/common/libimage/push.go index 47ab2cebaf0..9c4f5b38889 100644 --- a/vendor/github.com/containers/common/libimage/push.go +++ b/vendor/github.com/containers/common/libimage/push.go @@ -6,8 +6,6 @@ import ( dockerArchiveTransport "github.com/containers/image/v5/docker/archive" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/transports/alltransports" - "github.com/containers/storage" - "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -35,9 +33,6 @@ func (r *Runtime) Push(ctx context.Context, source, destination string, options if err != nil { return nil, err } - if image == nil { - return nil, errors.Wrap(storage.ErrImageUnknown, source) - } srcRef, err := image.StorageReference() if err != nil { diff --git a/vendor/github.com/containers/common/libimage/runtime.go b/vendor/github.com/containers/common/libimage/runtime.go index 3fcf236ee94..9c65b8a9110 100644 --- a/vendor/github.com/containers/common/libimage/runtime.go +++ b/vendor/github.com/containers/common/libimage/runtime.go @@ -13,7 +13,6 @@ import ( "github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/types" "github.com/containers/storage" - "github.com/hashicorp/go-multierror" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -117,8 +116,11 @@ func (r *Runtime) storageToImage(storageImage *storage.Image, ref types.ImageRef // Exists returns true if the specicifed image exists in the local containers // storage. func (r *Runtime) Exists(name string) (bool, error) { - image, _, err := r.LookupImage(name, nil) - return image != nil, err + image, _, err := r.LookupImage(name, &LookupImageOptions{IgnorePlatform: true}) + if err != nil && errors.Cause(err) != storage.ErrImageUnknown { + return false, err + } + return image != nil, nil } // LookupImageOptions allow for customizing local image lookups. @@ -131,9 +133,9 @@ type LookupImageOptions struct { // Lookup Image looks up `name` in the local container storage matching the // specified SystemContext. Returns the image and the name it has been found -// with. Returns nil if no image has been found. Note that name may also use -// the `containers-storage:` prefix used to refer to the containers-storage -// transport. +// with. Note that name may also use the `containers-storage:` prefix used to +// refer to the containers-storage transport. Returns storage.ErrImageUnknown +// if the image could not be found. // // If the specified name uses the `containers-storage` transport, the resolved // name is empty. @@ -158,50 +160,15 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image, return r.storageToImage(img, storageRef), "", nil } - byDigest := false + idByDigest := false if strings.HasPrefix(name, "sha256:") { - byDigest = true + idByDigest = true name = strings.TrimPrefix(name, "sha256:") } - // Anonymouns function to lookup the provided image in the storage and - // check whether it's matching the system context. - findImage := func(input string) (*Image, error) { - img, err := r.store.Image(input) - if err != nil && errors.Cause(err) != storage.ErrImageUnknown { - return nil, err - } - if img == nil { - return nil, nil - } - ref, err := storageTransport.Transport.ParseStoreReference(r.store, img.ID) - if err != nil { - return nil, err - } - - if options.IgnorePlatform { - logrus.Debugf("Found image %q as %q in local containers storage", name, input) - return r.storageToImage(img, ref), nil - } - - matches, err := imageReferenceMatchesContext(context.Background(), ref, &r.systemContext) - if err != nil { - return nil, err - } - if !matches { - return nil, nil - } - // Also print the string within the storage transport. That - // may aid in debugging when using additional stores since we - // see explicitly where the store is and which driver (options) - // are used. - logrus.Debugf("Found image %q as %q in local containers storage (%s)", name, input, ref.StringWithinTransport()) - return r.storageToImage(img, ref), nil - } - // First, check if we have an exact match in the storage. Maybe an ID // or a fully-qualified image name. - img, err := findImage(name) + img, err := r.lookupImageInLocalStorage(name, name, options) if err != nil { return nil, "", err } @@ -211,15 +178,15 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image, // If the name clearly referred to a local image, there's nothing we can // do anymore. - if storageRef != nil || byDigest { - return nil, "", nil + if storageRef != nil || idByDigest { + return nil, "", errors.Wrap(storage.ErrImageUnknown, name) } // Second, try out the candidates as resolved by shortnames. This takes // "localhost/" prefixed images into account as well. candidates, err := shortnames.ResolveLocally(&r.systemContext, name) if err != nil { - return nil, "", err + return nil, "", errors.Wrap(storage.ErrImageUnknown, name) } // Backwards compat: normalize to docker.io as some users may very well // rely on that. @@ -230,7 +197,7 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image, candidates = append(candidates, dockerNamed) for _, candidate := range candidates { - img, err := findImage(candidate.String()) + img, err := r.lookupImageInLocalStorage(name, candidate.String(), options) if err != nil { return nil, "", err } @@ -239,7 +206,157 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image, } } - return nil, "", nil + return r.lookupImageInDigestsAndRepoTags(name, options) +} + +// lookupImageInLocalStorage looks up the specified candidate for name in the +// storage and checks whether it's matching the system context. +func (r *Runtime) lookupImageInLocalStorage(name, candidate string, options *LookupImageOptions) (*Image, error) { + logrus.Debugf("Trying %q ...", candidate) + img, err := r.store.Image(candidate) + if err != nil && errors.Cause(err) != storage.ErrImageUnknown { + return nil, err + } + if img == nil { + return nil, nil + } + ref, err := storageTransport.Transport.ParseStoreReference(r.store, img.ID) + if err != nil { + return nil, err + } + + image := r.storageToImage(img, ref) + if options.IgnorePlatform { + logrus.Debugf("Found image %q as %q in local containers storage", name, candidate) + return image, nil + } + + // If we referenced a manifest list, we need to check whether we can + // find a matching instance in the local containers storage. + isManifestList, err := image.IsManifestList(context.Background()) + if err != nil { + return nil, err + } + if isManifestList { + manifestList, err := image.ToManifestList() + if err != nil { + return nil, err + } + image, err = manifestList.LookupInstance(context.Background(), "", "", "") + if err != nil { + return nil, err + } + ref, err = storageTransport.Transport.ParseStoreReference(r.store, "@"+image.ID()) + if err != nil { + return nil, err + } + } + + matches, err := imageReferenceMatchesContext(context.Background(), ref, &r.systemContext) + if err != nil { + return nil, err + } + if !matches { + return nil, nil + } + // Also print the string within the storage transport. That may aid in + // debugging when using additional stores since we see explicitly where + // the store is and which driver (options) are used. + logrus.Debugf("Found image %q as %q in local containers storage (%s)", name, candidate, ref.StringWithinTransport()) + return image, nil +} + +// lookupImageInDigestsAndRepoTags attempts to match name against any image in +// the local containers storage. If name is digested, it will be compared +// against image digests. Otherwise, it will be looked up in the repo tags. +func (r *Runtime) lookupImageInDigestsAndRepoTags(name string, options *LookupImageOptions) (*Image, string, error) { + // Until now, we've tried very hard to find an image but now it is time + // for limbo. If the image includes a digest that we couldn't detect + // verbatim in the storage, we must have a look at all digests of all + // images. Those may change over time (e.g., via manifest lists). + // Both Podman and Buildah want us to do that dance. + allImages, err := r.ListImages(context.Background(), nil, nil) + if err != nil { + return nil, "", err + } + + if !shortnames.IsShortName(name) { + named, err := NormalizeName(name) + if err != nil { + return nil, "", err + } + digested, hasDigest := named.(reference.Digested) + if !hasDigest { + return nil, "", errors.Wrap(storage.ErrImageUnknown, name) + } + + logrus.Debug("Looking for image with matching recorded digests") + digest := digested.Digest() + for _, image := range allImages { + for _, d := range image.Digests() { + if d == digest { + return image, name, nil + } + } + } + + return nil, "", errors.Wrap(storage.ErrImageUnknown, name) + } + + // Podman compat: if we're looking for a short name but couldn't + // resolve it via the registries.conf dance, we need to look at *all* + // images and check if the name we're looking for matches a repo tag. + // Split the name into a repo/tag pair + split := strings.SplitN(name, ":", 2) + repo := split[0] + tag := "" + if len(split) == 2 { + tag = split[1] + } + for _, image := range allImages { + named, err := image.inRepoTags(repo, tag) + if err != nil { + return nil, "", err + } + if named == nil { + continue + } + img, err := r.lookupImageInLocalStorage(name, named.String(), options) + if err != nil { + return nil, "", err + } + if img != nil { + return img, named.String(), err + } + } + + return nil, "", errors.Wrap(storage.ErrImageUnknown, name) +} + +// ResolveName resolves the specified name. If the name resolves to a local +// image, the fully resolved name will be returned. Otherwise, the name will +// be properly normalized. +// +// Note that an empty string is returned as is. +func (r *Runtime) ResolveName(name string) (string, error) { + if name == "" { + return "", nil + } + image, resolvedName, err := r.LookupImage(name, &LookupImageOptions{IgnorePlatform: true}) + if err != nil && errors.Cause(err) != storage.ErrImageUnknown { + return "", err + } + + if image != nil && !strings.HasPrefix(image.ID(), resolvedName) { + return resolvedName, err + } + + normalized, err := NormalizeName(name) + if err != nil { + return "", err + } + + return normalized.String(), nil } // imageReferenceMatchesContext return true if the specified reference matches @@ -301,9 +418,6 @@ func (r *Runtime) ListImages(ctx context.Context, names []string, options *ListI if err != nil { return nil, err } - if image == nil { - return nil, errors.Wrap(storage.ErrImageUnknown, name) - } images = append(images, image) } } else { @@ -341,6 +455,25 @@ type RemoveImagesOptions struct { // * readonly=true,false // * reference=name[:tag] (wildcards allowed) Filters []string + + // The RemoveImagesReport will include the size of the removed image. + // This information may be useful when pruning images to figure out how + // much space was freed. However, computing the size of an image is + // comparatively expensive, so it is made optional. + WithSize bool +} + +// RemoveImagesReport is the assembled data from removing *one* image. +type RemoveImagesReport struct { + // ID of the image. + ID string + // Image was removed. + Removed bool + // Size of the removed image. Only set when explicitly requested in + // RemoveImagesOptions. + Size int64 + // The untagged tags. + Untagged []string } // RemoveImages removes images specified by names. All images are expected to @@ -349,7 +482,10 @@ type RemoveImagesOptions struct { // If an image has more names than one name, the image will be untagged with // the specified name. RemoveImages returns a slice of untagged and removed // images. -func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *RemoveImagesOptions) (untagged, removed []string, rmError error) { +// +// Note that most errors are non-fatal and collected into `rmErrors` return +// value. +func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *RemoveImagesOptions) (reports []*RemoveImagesReport, rmErrors []error) { if options == nil { options = &RemoveImagesOptions{} } @@ -362,6 +498,12 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem name string } + appendError := func(err error) { + rmErrors = append(rmErrors, err) + } + + reportMap := make(map[string]*RemoveImagesReport) // to assemble data + var images []*deleteMe switch { case len(names) > 0: @@ -369,21 +511,20 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem for _, name := range names { img, resolvedName, err := r.LookupImage(name, &lookupOptions) if err != nil { - return nil, nil, err - } - if img == nil { - return nil, nil, errors.Wrap(storage.ErrImageUnknown, name) + appendError(err) + continue } images = append(images, &deleteMe{image: img, name: resolvedName}) } if len(images) == 0 { - return nil, nil, errors.New("no images found") + return nil, rmErrors } case len(options.Filters) > 0: filteredImages, err := r.ListImages(ctx, nil, &ListImagesOptions{Filters: options.Filters}) if err != nil { - return nil, nil, err + appendError(err) + return nil, rmErrors } for _, img := range filteredImages { images = append(images, &deleteMe{image: img}) @@ -392,26 +533,44 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem // Now remove the images. for _, delete := range images { + report, exists := reportMap[delete.image.ID()] + if !exists { + report = &RemoveImagesReport{ID: delete.image.ID()} + if options.WithSize { + size, err := delete.image.Size() + if err != nil { + appendError(errors.Wrap(err, "error determining size")) + continue + } + report.Size = size + } + // Append a report only once. This also preserves the + // relative order. + reports = append(reports, report) + } + numNames := len(delete.image.Names()) skipRemove := false if len(names) > 0 { hasChildren, err := delete.image.HasChildren(ctx) if err != nil { - rmError = multierror.Append(rmError, err) - continue + // See Podman commit fd9dd7065d44: we need to + // be tolerant toward corrupted images. + logrus.Warnf("error determining if an image is a parent: %v, ignoring the error", err) + hasChildren = false } skipRemove = hasChildren } if delete.name != "" { - untagged = append(untagged, delete.name) + report.Untagged = append(report.Untagged, delete.name) } mustUntag := !options.Force && delete.name != "" && (numNames > 1 || skipRemove) if mustUntag { if err := delete.image.Untag(delete.name); err != nil { - rmError = multierror.Append(rmError, err) + appendError(errors.Wrap(err, "error untagging")) continue } // If the untag did not reduce the image names, name @@ -420,7 +579,7 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem newNumNames := len(delete.image.Names()) if newNumNames == numNames && newNumNames != 1 { err := errors.Errorf("unable to delete image %q by ID with more than one tag (%s): use force removal", delete.image.ID(), delete.image.Names()) - rmError = multierror.Append(rmError, err) + appendError(err) continue } @@ -436,13 +595,19 @@ func (r *Runtime) RemoveImages(ctx context.Context, names []string, options *Rem // If the image does not exist (anymore) we are good. // We already performed a presence check in the image // look up when `names` are specified. - if errors.Cause(err) != storage.ErrImageUnknown { - rmError = multierror.Append(rmError, err) + switch errors.Cause(err) { + case storage.ErrImageUnknown, storage.ErrNotAnImage, storage.ErrLayerUnknown: + // The image or layers of the image may already + // have been removed in which case we consider + // the image to be removed. + default: + // All other errors are reported. + appendError(errors.Wrap(err, delete.image.ID())) continue } } - removed = append(removed, delete.image.ID()) + report.Removed = true } - return untagged, removed, rmError + return reports, rmErrors } diff --git a/vendor/github.com/containers/common/libimage/save.go b/vendor/github.com/containers/common/libimage/save.go index 5b842896a0f..95534fc015b 100644 --- a/vendor/github.com/containers/common/libimage/save.go +++ b/vendor/github.com/containers/common/libimage/save.go @@ -77,7 +77,7 @@ func (r *Runtime) saveSingleImage(ctx context.Context, name, format, path string // Unless the image was referenced by ID, use the resolved name as a // tag. var tag string - if strings.HasPrefix(image.ID(), imageName) { + if !strings.HasPrefix(image.ID(), imageName) { tag = imageName } diff --git a/vendor/github.com/containers/common/libimage/search.go b/vendor/github.com/containers/common/libimage/search.go index d58d50ba372..f0e9d65b1a4 100644 --- a/vendor/github.com/containers/common/libimage/search.go +++ b/vendor/github.com/containers/common/libimage/search.go @@ -3,6 +3,7 @@ package libimage import ( "context" "fmt" + "strconv" "strings" "sync" @@ -69,13 +70,47 @@ type SearchFilter struct { IsOfficial types.OptionalBool } -func (r *Runtime) Search(ctx context.Context, term string, options SearchOptions) ([]SearchResult, error) { - searchRegistries, err := sysregistriesv2.UnqualifiedSearchRegistries(&r.systemContext) - if err != nil { - return nil, err +// ParseSearchFilter turns the filter into a SearchFilter that can be used for +// searching images. +func ParseSearchFilter(filter []string) (*SearchFilter, error) { + sFilter := new(SearchFilter) + for _, f := range filter { + arr := strings.SplitN(f, "=", 2) + switch arr[0] { + case "stars": + if len(arr) < 2 { + return nil, errors.Errorf("invalid `stars` filter %q, should be stars=", filter) + } + stars, err := strconv.Atoi(arr[1]) + if err != nil { + return nil, errors.Wrapf(err, "incorrect value type for stars filter") + } + sFilter.Stars = stars + case "is-automated": + if len(arr) == 2 && arr[1] == "false" { + sFilter.IsAutomated = types.OptionalBoolFalse + } else { + sFilter.IsAutomated = types.OptionalBoolTrue + } + case "is-official": + if len(arr) == 2 && arr[1] == "false" { + sFilter.IsOfficial = types.OptionalBoolFalse + } else { + sFilter.IsOfficial = types.OptionalBoolTrue + } + default: + return nil, errors.Errorf("invalid filter type %q", f) + } + } + return sFilter, nil +} + +func (r *Runtime) Search(ctx context.Context, term string, options *SearchOptions) ([]SearchResult, error) { + if options == nil { + options = &SearchOptions{} } - logrus.Debugf("Searching images matching term %s at the following registries %s", term, searchRegistries) + var searchRegistries []string // Try to extract a registry from the specified search term. We // consider everything before the first slash to be the registry. Note @@ -85,8 +120,16 @@ func (r *Runtime) Search(ctx context.Context, term string, options SearchOptions if spl := strings.SplitN(term, "/", 2); len(spl) > 1 { searchRegistries = append(searchRegistries, spl[0]) term = spl[1] + } else { + regs, err := sysregistriesv2.UnqualifiedSearchRegistries(&r.systemContext) + if err != nil { + return nil, err + } + searchRegistries = regs } + logrus.Debugf("Searching images matching term %s at the following registries %s", term, searchRegistries) + // searchOutputData is used as a return value for searching in parallel. type searchOutputData struct { data []SearchResult @@ -130,7 +173,7 @@ func (r *Runtime) Search(ctx context.Context, term string, options SearchOptions return results, multiErr } -func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry string, options SearchOptions) ([]SearchResult, error) { +func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry string, options *SearchOptions) ([]SearchResult, error) { // Max number of queries by default is 25 limit := searchMaxQueries if options.Limit > 0 { @@ -209,7 +252,7 @@ func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry stri return paramsArr, nil } -func searchRepositoryTags(ctx context.Context, sys *types.SystemContext, registry, term string, options SearchOptions) ([]SearchResult, error) { +func searchRepositoryTags(ctx context.Context, sys *types.SystemContext, registry, term string, options *SearchOptions) ([]SearchResult, error) { dockerPrefix := "docker://" imageRef, err := alltransports.ParseImageName(fmt.Sprintf("%s/%s", registry, term)) if err == nil && imageRef.Transport().Name() != dockerTransport.Transport.Name() { diff --git a/vendor/github.com/containers/common/libimage/types/types.go b/vendor/github.com/containers/common/libimage/types/types.go deleted file mode 100644 index 9924bc813ed..00000000000 --- a/vendor/github.com/containers/common/libimage/types/types.go +++ /dev/null @@ -1,58 +0,0 @@ -package types - -import ( - "time" - - "github.com/containers/image/v5/manifest" - "github.com/opencontainers/go-digest" - ociv1 "github.com/opencontainers/image-spec/specs-go/v1" -) - -// ImageData contains the inspected data of an image. -type ImageData struct { - ID string `json:"Id"` - Digest digest.Digest `json:"Digest"` - RepoTags []string `json:"RepoTags"` - RepoDigests []string `json:"RepoDigests"` - Parent string `json:"Parent"` - Comment string `json:"Comment"` - Created *time.Time `json:"Created"` - Config *ociv1.ImageConfig `json:"Config"` - Version string `json:"Version"` - Author string `json:"Author"` - Architecture string `json:"Architecture"` - Os string `json:"Os"` - Size int64 `json:"Size"` - VirtualSize int64 `json:"VirtualSize"` - GraphDriver *DriverData `json:"GraphDriver"` - RootFS *RootFS `json:"RootFS"` - Labels map[string]string `json:"Labels"` - Annotations map[string]string `json:"Annotations"` - ManifestType string `json:"ManifestType"` - User string `json:"User"` - History []ociv1.History `json:"History"` - NamesHistory []string `json:"NamesHistory"` - HealthCheck *manifest.Schema2HealthConfig `json:"Healthcheck,omitempty"` -} - -// DriverData includes data on the storage driver of the image. -type DriverData struct { - Name string `json:"Name"` - Data map[string]string `json:"Data"` -} - -// RootFS includes data on the root filesystem of the image. -type RootFS struct { - Type string `json:"Type"` - Layers []digest.Digest `json:"Layers"` -} - -// ImageHistory contains the history information of an image. -type ImageHistory struct { - ID string `json:"id"` - Created *time.Time `json:"created"` - CreatedBy string `json:"createdBy"` - Size int64 `json:"size"` - Comment string `json:"comment"` - Tags []string `json:"tags"` -} diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index 1629bea29df..371dd366762 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -47,18 +47,6 @@ const ( BoltDBStateStore RuntimeStateStore = iota ) -// PullPolicy whether to pull new image -type PullPolicy int - -const ( - // PullImageAlways always try to pull new image when create or run - PullImageAlways PullPolicy = iota - // PullImageMissing pulls image if it is not locally - PullImageMissing - // PullImageNever will never pull new image - PullImageNever -) - // Config contains configuration options for container tools type Config struct { // Containers specify settings that configure how containers will run ont the system @@ -263,6 +251,9 @@ type EngineConfig struct { // LockType is the type of locking to use. LockType string `toml:"lock_type,omitempty"` + // MachineEnabled indicates if Podman is running in a podman-machine VM + MachineEnabled bool `toml:"machine_enabled,omitempty"` + // MultiImageArchive - if true, the container engine allows for storing // archives (e.g., of the docker-archive transport) with multiple // images. By default, Podman creates single-image archives. @@ -697,23 +688,6 @@ func (c *NetworkConfig) Validate() error { return errors.Errorf("invalid cni_plugin_dirs: %s", strings.Join(c.CNIPluginDirs, ",")) } -// ValidatePullPolicy check if the pullPolicy from CLI is valid and returns the valid enum type -// if the value from CLI or containers.conf is invalid returns the error -func ValidatePullPolicy(pullPolicy string) (PullPolicy, error) { - switch strings.ToLower(pullPolicy) { - case "always": - return PullImageAlways, nil - case "missing", "ifnotpresent": - return PullImageMissing, nil - case "never": - return PullImageNever, nil - case "": - return PullImageMissing, nil - default: - return PullImageMissing, errors.Errorf("invalid pull policy %q", pullPolicy) - } -} - // FindConmon iterates over (*Config).ConmonPath and returns the path // to first (version) matching conmon binary. If non is found, we try // to do a path lookup of "conmon". diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf index 0114f297579..00edd543831 100644 --- a/vendor/github.com/containers/common/pkg/config/containers.conf +++ b/vendor/github.com/containers/common/pkg/config/containers.conf @@ -336,6 +336,11 @@ default_sysctls = [ # # lock_type** = "shm" +# Indicates if Podman is running inside a VM via Podman Machine. +# Podman uses this value to do extra setup around networking from the +# container inside the VM to to host. +# machine_enabled=false + # MultiImageArchive - if true, the container engine allows for storing archives # (e.g., of the docker-archive transport) with multiple images. By default, # Podman creates single-image archives. @@ -403,7 +408,7 @@ default_sysctls = [ # List of the OCI runtimes that support --format=json. When json is supported # engine will use it for reporting nicer errors. # -# runtime_supports_json = ["crun", "runc", "kata"] +# runtime_supports_json = ["crun", "runc", "kata", "runsc"] # List of the OCI runtimes that supports running containers without cgroups. # @@ -432,7 +437,7 @@ default_sysctls = [ # Path to file containing ssh identity key # identity = "~/.ssh/id_rsa" -# Paths to look for a valid OCI runtime (crun, runc, kata, etc) +# Paths to look for a valid OCI runtime (crun, runc, kata, runsc, etc) [engine.runtimes] # crun = [ # "/usr/bin/crun", @@ -465,6 +470,16 @@ default_sysctls = [ # "/usr/bin/kata-fc", # ] +# runsc = [ +# "/usr/bin/runsc", +# "/usr/sbin/runsc", +# "/usr/local/bin/runsc", +# "/usr/local/sbin/runsc", +# "/bin/runsc", +# "/sbin/runsc", +# "/run/current-system/sw/bin/runsc", +# ] + [engine.volume_plugins] # testplugin = "/run/podman/plugins/test.sock" diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go index 72744bb12c3..34a360bf57f 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -278,6 +278,15 @@ func defaultConfigFromMemory() (*EngineConfig, error) { "/usr/bin/kata-qemu", "/usr/bin/kata-fc", }, + "runsc": { + "/usr/bin/runsc", + "/usr/sbin/runsc", + "/usr/local/bin/runsc", + "/usr/local/sbin/runsc", + "/bin/runsc", + "/sbin/runsc", + "/run/current-system/sw/bin/runsc", + }, } // Needs to be called after populating c.OCIRuntimes c.OCIRuntime = c.findRuntime() @@ -299,6 +308,8 @@ func defaultConfigFromMemory() (*EngineConfig, error) { c.RuntimeSupportsJSON = []string{ "crun", "runc", + "kata", + "runsc", } c.RuntimeSupportsNoCgroups = []string{"crun"} c.RuntimeSupportsKVM = []string{"kata", "kata-runtime", "kata-qemu", "kata-fc"} @@ -314,6 +325,7 @@ func defaultConfigFromMemory() (*EngineConfig, error) { // TODO - ideally we should expose a `type LockType string` along with // constants. c.LockType = "shm" + c.MachineEnabled = false return c, nil } @@ -524,3 +536,7 @@ func (c *Config) Umask() string { func (c *Config) LogDriver() string { return c.Containers.LogDriver } + +func (c *Config) MachineEnabled() bool { + return c.Engine.MachineEnabled +} diff --git a/vendor/github.com/containers/common/libimage/types/pull_policy.go b/vendor/github.com/containers/common/pkg/config/pull_policy.go similarity index 83% rename from vendor/github.com/containers/common/libimage/types/pull_policy.go rename to vendor/github.com/containers/common/pkg/config/pull_policy.go index 69e36ed6cb4..7c32dd660cb 100644 --- a/vendor/github.com/containers/common/libimage/types/pull_policy.go +++ b/vendor/github.com/containers/common/pkg/config/pull_policy.go @@ -1,4 +1,4 @@ -package types +package config import ( "fmt" @@ -17,23 +17,23 @@ import ( type PullPolicy int const ( - // This default value forces callers to setup a custom default policy. - // Some tools use different policies (e.g., buildah-bud versus - // podman-build). - PullPolicyUnsupported PullPolicy = iota // Always pull the image. - PullPolicyAlways + PullPolicyAlways PullPolicy = iota // Pull the image only if it could not be found in the local containers // storage. PullPolicyMissing + // Never pull the image but use the one from the local containers + // storage. + PullPolicyNever // Pull if the image on the registry is new than the one in the local // containers storage. An image is considered to be newer when the // digests are different. Comparing the time stamps is prone to // errors. PullPolicyNewer - // Never pull the image but use the one from the local containers - // storage. - PullPolicyNever + + // Ideally this should be the first `ioata` but backwards compatibility + // prevents us from changing the values. + PullPolicyUnsupported = -1 ) // String converts a PullPolicy into a string. @@ -71,14 +71,14 @@ func (p PullPolicy) Validate() error { // // Supported string values are: // * "always" <-> PullPolicyAlways -// * "missing" <-> PullPolicyMissing +// * "missing" <-> PullPolicyMissing (also "ifnotpresent" and "") // * "newer" <-> PullPolicyNewer (also "ifnewer") // * "never" <-> PullPolicyNever func ParsePullPolicy(s string) (PullPolicy, error) { switch s { case "always": return PullPolicyAlways, nil - case "missing": + case "missing", "ifnotpresent", "": return PullPolicyMissing, nil case "newer", "ifnewer": return PullPolicyNewer, nil @@ -88,3 +88,8 @@ func ParsePullPolicy(s string) (PullPolicy, error) { return PullPolicyUnsupported, errors.Errorf("unsupported pull policy %q", s) } } + +// Deprecated: please use `ParsePullPolicy` instead. +func ValidatePullPolicy(s string) (PullPolicy, error) { + return ParsePullPolicy(s) +} diff --git a/vendor/github.com/containers/common/pkg/filters/filters.go b/vendor/github.com/containers/common/pkg/filters/filters.go index 22222d33d4d..53f420db29a 100644 --- a/vendor/github.com/containers/common/pkg/filters/filters.go +++ b/vendor/github.com/containers/common/pkg/filters/filters.go @@ -69,9 +69,11 @@ func FiltersFromRequest(r *http.Request) ([]string, error) { } for filterKey, filterSlice := range filters { + f := filterKey for _, filterValue := range filterSlice { - libpodFilters = append(libpodFilters, fmt.Sprintf("%s=%s", filterKey, filterValue)) + f += "=" + filterValue } + libpodFilters = append(libpodFilters, f) } return libpodFilters, nil diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index d9e7ffec7fb..8db12849474 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.37.0" +const Version = "0.37.1-dev" diff --git a/vendor/github.com/disiqueira/gotree/v3/.gitignore b/vendor/github.com/disiqueira/gotree/v3/.gitignore new file mode 100644 index 00000000000..3236c30ab6a --- /dev/null +++ b/vendor/github.com/disiqueira/gotree/v3/.gitignore @@ -0,0 +1,137 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +.idea/ +GoTree.iml +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* +### Windows template +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/workspace.xml +.idea/tasks.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +### Go template +# Compiled Object files, Static and Dynamic libs (Shared Objects) + +# Folders + +# Architecture specific extensions/prefixes + + + +### OSX template +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/vendor/github.com/disiqueira/gotree/v3/.travis.yml b/vendor/github.com/disiqueira/gotree/v3/.travis.yml new file mode 100644 index 00000000000..29261dfffe1 --- /dev/null +++ b/vendor/github.com/disiqueira/gotree/v3/.travis.yml @@ -0,0 +1,11 @@ +language: go +go_import_path: github.com/disiqueira/gotree +git: + depth: 1 +env: + - GO111MODULE=on + - GO111MODULE=off +go: [ 1.11.x, 1.12.x, 1.13.x ] +os: [ linux, osx ] +script: + - go test -race -v ./... diff --git a/vendor/github.com/disiqueira/gotree/v3/LICENSE b/vendor/github.com/disiqueira/gotree/v3/LICENSE new file mode 100644 index 00000000000..e790b5a5231 --- /dev/null +++ b/vendor/github.com/disiqueira/gotree/v3/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Diego Siqueira + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/disiqueira/gotree/v3/README.md b/vendor/github.com/disiqueira/gotree/v3/README.md new file mode 100644 index 00000000000..d09d4a98cda --- /dev/null +++ b/vendor/github.com/disiqueira/gotree/v3/README.md @@ -0,0 +1,104 @@ +# ![GoTree](https://rawgit.com/DiSiqueira/GoTree/master/gotree-logo.png) + +# GoTree ![Language Badge](https://img.shields.io/badge/Language-Go-blue.svg) ![Go Report](https://goreportcard.com/badge/github.com/DiSiqueira/GoTree) ![License Badge](https://img.shields.io/badge/License-MIT-blue.svg) ![Status Badge](https://img.shields.io/badge/Status-Beta-brightgreen.svg) [![GoDoc](https://godoc.org/github.com/DiSiqueira/GoTree?status.svg)](https://godoc.org/github.com/DiSiqueira/GoTree) [![Build Status](https://travis-ci.org/DiSiqueira/GoTree.svg?branch=master)](https://travis-ci.org/DiSiqueira/GoTree) + +Simple Go module to print tree structures in terminal. Heavily inpired by [The Tree Command for Linux][treecommand] + +The GoTree's goal is to be a simple tool providing a stupidly easy-to-use and fast way to print recursive structures. + +[treecommand]: http://mama.indstate.edu/users/ice/tree/ + +## Project Status + +GoTree is on beta. Pull Requests [are welcome](https://github.com/DiSiqueira/GoTree#social-coding) + +![](http://image.prntscr.com/image/2a0dbf0777454446b8083fb6a0dc51fe.png) + +## Features + +- Very simple and fast code +- Intuitive names +- Easy to extend +- Uses only native libs +- STUPIDLY [EASY TO USE](https://github.com/DiSiqueira/GoTree#usage) + +## Installation + +### Go Get + +```bash +$ go get github.com/disiqueira/gotree +``` + +## Usage + +### Simple create, populate and print example + +![](http://image.prntscr.com/image/dd2fe3737e6543f7b21941a6953598c2.png) + +```golang +package main + +import ( + "fmt" + + "github.com/disiqueira/gotree" +) + +func main() { + artist := gotree.New("Pantera") + album := artist.Add("Far Beyond Driven") + album.Add("5 minutes Alone") + + fmt.Println(artist.Print()) +} +``` + +## Contributing + +### Bug Reports & Feature Requests + +Please use the [issue tracker](https://github.com/DiSiqueira/GoTree/issues) to report any bugs or file feature requests. + +### Developing + +PRs are welcome. To begin developing, do this: + +```bash +$ git clone --recursive git@github.com:DiSiqueira/GoTree.git +$ cd GoTree/ +``` + +## Social Coding + +1. Create an issue to discuss about your idea +2. [Fork it] (https://github.com/DiSiqueira/GoTree/fork) +3. Create your feature branch (`git checkout -b my-new-feature`) +4. Commit your changes (`git commit -am 'Add some feature'`) +5. Push to the branch (`git push origin my-new-feature`) +6. Create a new Pull Request +7. Profit! :white_check_mark: + +## License + +The MIT License (MIT) + +Copyright (c) 2013-2018 Diego Siqueira + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/disiqueira/gotree/v3/_config.yml b/vendor/github.com/disiqueira/gotree/v3/_config.yml new file mode 100644 index 00000000000..c7418817439 --- /dev/null +++ b/vendor/github.com/disiqueira/gotree/v3/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file diff --git a/vendor/github.com/disiqueira/gotree/v3/go.mod b/vendor/github.com/disiqueira/gotree/v3/go.mod new file mode 100644 index 00000000000..7e17c637e45 --- /dev/null +++ b/vendor/github.com/disiqueira/gotree/v3/go.mod @@ -0,0 +1,3 @@ +module github.com/disiqueira/gotree/v3 + +go 1.13 diff --git a/vendor/github.com/disiqueira/gotree/v3/gotree-logo.png b/vendor/github.com/disiqueira/gotree/v3/gotree-logo.png new file mode 100644 index 00000000000..1735c6008d6 Binary files /dev/null and b/vendor/github.com/disiqueira/gotree/v3/gotree-logo.png differ diff --git a/vendor/github.com/disiqueira/gotree/v3/gotree.go b/vendor/github.com/disiqueira/gotree/v3/gotree.go new file mode 100644 index 00000000000..c529f62be0b --- /dev/null +++ b/vendor/github.com/disiqueira/gotree/v3/gotree.go @@ -0,0 +1,129 @@ +// Package gotree create and print tree. +package gotree + +import ( + "strings" +) + +const ( + newLine = "\n" + emptySpace = " " + middleItem = "├── " + continueItem = "│ " + lastItem = "└── " +) + +type ( + tree struct { + text string + items []Tree + } + + // Tree is tree interface + Tree interface { + Add(text string) Tree + AddTree(tree Tree) + Items() []Tree + Text() string + Print() string + } + + printer struct { + } + + // Printer is printer interface + Printer interface { + Print(Tree) string + } +) + +//New returns a new GoTree.Tree +func New(text string) Tree { + return &tree{ + text: text, + items: []Tree{}, + } +} + +//Add adds a node to the tree +func (t *tree) Add(text string) Tree { + n := New(text) + t.items = append(t.items, n) + return n +} + +//AddTree adds a tree as an item +func (t *tree) AddTree(tree Tree) { + t.items = append(t.items, tree) +} + +//Text returns the node's value +func (t *tree) Text() string { + return t.text +} + +//Items returns all items in the tree +func (t *tree) Items() []Tree { + return t.items +} + +//Print returns an visual representation of the tree +func (t *tree) Print() string { + return newPrinter().Print(t) +} + +func newPrinter() Printer { + return &printer{} +} + +//Print prints a tree to a string +func (p *printer) Print(t Tree) string { + return t.Text() + newLine + p.printItems(t.Items(), []bool{}) +} + +func (p *printer) printText(text string, spaces []bool, last bool) string { + var result string + for _, space := range spaces { + if space { + result += emptySpace + } else { + result += continueItem + } + } + + indicator := middleItem + if last { + indicator = lastItem + } + + var out string + lines := strings.Split(text, "\n") + for i := range lines { + text := lines[i] + if i == 0 { + out += result + indicator + text + newLine + continue + } + if last { + indicator = emptySpace + } else { + indicator = continueItem + } + out += result + indicator + text + newLine + } + + return out +} + +func (p *printer) printItems(t []Tree, spaces []bool) string { + var result string + for i, f := range t { + last := i == len(t)-1 + result += p.printText(f.Text(), spaces, last) + if len(f.Items()) > 0 { + spacesChild := append(spaces, last) + result += p.printItems(f.Items(), spacesChild) + } + } + return result +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 077004e4c93..13c05947e5d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -60,10 +60,9 @@ github.com/containernetworking/cni/pkg/types/020 github.com/containernetworking/cni/pkg/types/current github.com/containernetworking/cni/pkg/utils github.com/containernetworking/cni/pkg/version -# github.com/containers/common v0.37.0 +# github.com/containers/common v0.37.0 => github.com/vrothberg/common v0.0.3-0.20210430070256-9bc69171635f github.com/containers/common/libimage github.com/containers/common/libimage/manifests -github.com/containers/common/libimage/types github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/apparmor/internal/supported github.com/containers/common/pkg/auth @@ -192,6 +191,8 @@ github.com/containers/storage/types github.com/coreos/go-systemd/v22/dbus # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew +# github.com/disiqueira/gotree/v3 v3.0.2 +github.com/disiqueira/gotree/v3 # github.com/docker/distribution v2.7.1+incompatible github.com/docker/distribution github.com/docker/distribution/digestset