Vendor in latest containers/common

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh
2024-02-27 16:20:50 -05:00
parent 98d1ad5a22
commit 2c9c7273ca
19 changed files with 365 additions and 90 deletions

View File

@ -19,6 +19,7 @@ import (
structcopier "github.com/jinzhu/copier"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"
)
@ -294,7 +295,7 @@ func (m *ManifestList) Inspect() (*define.ManifestListData, error) {
return &inspectList, nil
}
// Options for adding a manifest list.
// Options for adding an image or artifact to a manifest list.
type ManifestListAddOptions struct {
// Add all images to the list if the to-be-added image itself is a
// manifest list.
@ -371,6 +372,104 @@ func (m *ManifestList) Add(ctx context.Context, name string, options *ManifestLi
return newDigest, nil
}
// Options for creating an artifact manifest for one or more files and adding
// the artifact manifest to a manifest list.
type ManifestListAddArtifactOptions struct {
// The artifactType to set in the artifact manifest.
Type *string `json:"artifact_type"`
// The mediaType to set in the config.MediaType field in the artifact manifest.
ConfigType string `json:"artifact_config_type"`
// Content to point to from the config field in the artifact manifest.
Config string `json:"artifact_config"`
// The mediaType to set in the layer descriptors in the artifact manifest.
LayerType string `json:"artifact_layer_type"`
// Whether or not to suppress the org.opencontainers.image.title annotation in layer descriptors.
ExcludeTitles bool `json:"exclude_layer_titles"`
// Annotations to set in the artifact manifest.
Annotations map[string]string `json:"annotations"`
// Subject to set in the artifact manifest.
Subject string `json:"subject"`
}
// Add adds one or more manifests to the manifest list and returns the digest
// of the added instance.
func (m *ManifestList) AddArtifact(ctx context.Context, options *ManifestListAddArtifactOptions, files ...string) (digest.Digest, error) {
if options == nil {
options = &ManifestListAddArtifactOptions{}
}
opts := manifests.AddArtifactOptions{
ManifestArtifactType: options.Type,
Annotations: maps.Clone(options.Annotations),
ExcludeTitles: options.ExcludeTitles,
}
if options.ConfigType != "" {
opts.ConfigDescriptor = &imgspecv1.Descriptor{
MediaType: options.ConfigType,
Digest: imgspecv1.DescriptorEmptyJSON.Digest,
Size: imgspecv1.DescriptorEmptyJSON.Size,
Data: slices.Clone(imgspecv1.DescriptorEmptyJSON.Data),
}
}
if options.Config != "" {
if opts.ConfigDescriptor == nil {
opts.ConfigDescriptor = &imgspecv1.Descriptor{
MediaType: imgspecv1.MediaTypeImageConfig,
}
}
opts.ConfigDescriptor.Digest = digest.FromString(options.Config)
opts.ConfigDescriptor.Size = int64(len(options.Config))
opts.ConfigDescriptor.Data = slices.Clone([]byte(options.Config))
}
if opts.ConfigDescriptor == nil {
empty := imgspecv1.DescriptorEmptyJSON
opts.ConfigDescriptor = &empty
}
if options.LayerType != "" {
opts.LayerMediaType = &options.LayerType
}
if options.Subject != "" {
ref, err := alltransports.ParseImageName(options.Subject)
if err != nil {
withDocker := fmt.Sprintf("%s://%s", docker.Transport.Name(), options.Subject)
ref, err = alltransports.ParseImageName(withDocker)
if err != nil {
image, _, err := m.image.runtime.LookupImage(options.Subject, &LookupImageOptions{ManifestList: true})
if err != nil {
return "", fmt.Errorf("locating subject for artifact manifest: %w", err)
}
ref = image.storageReference
}
}
opts.SubjectReference = ref
}
// Lock the image record where this list lives.
locker, err := manifests.LockerForImage(m.image.runtime.store, m.ID())
if err != nil {
return "", err
}
locker.Lock()
defer locker.Unlock()
systemContext := m.image.runtime.systemContextCopy()
// Make sure to reload the image from the containers storage to fetch
// the latest data (e.g., new or delete digests).
if err := m.reload(); err != nil {
return "", err
}
newDigest, err := m.list.AddArtifact(ctx, systemContext, opts, files...)
if err != nil {
return "", err
}
// Write the changes to disk.
if err := m.saveAndReload(); err != nil {
return "", err
}
return newDigest, nil
}
// Options for annotating a manifest list.
type ManifestListAnnotateOptions struct {
// Add the specified annotations to the added image.
@ -387,10 +486,16 @@ type ManifestListAnnotateOptions struct {
OSVersion string
// Add the specified variant to the added image.
Variant string
// Add the specified annotations to the index itself.
IndexAnnotations map[string]string
// Set the subject to which the index refers.
Subject string
}
// Annotate an image instance specified by `d` in the manifest list.
func (m *ManifestList) AnnotateInstance(d digest.Digest, options *ManifestListAnnotateOptions) error {
ctx := context.Background()
if options == nil {
return nil
}
@ -430,6 +535,54 @@ func (m *ManifestList) AnnotateInstance(d digest.Digest, options *ManifestListAn
return err
}
}
if len(options.IndexAnnotations) > 0 {
if err := m.list.SetAnnotations(nil, options.IndexAnnotations); err != nil {
return err
}
}
if options.Subject != "" {
ref, err := alltransports.ParseImageName(options.Subject)
if err != nil {
withDocker := fmt.Sprintf("%s://%s", docker.Transport.Name(), options.Subject)
ref, err = alltransports.ParseImageName(withDocker)
if err != nil {
image, _, err := m.image.runtime.LookupImage(options.Subject, &LookupImageOptions{ManifestList: true})
if err != nil {
return fmt.Errorf("locating subject for image index: %w", err)
}
ref = image.storageReference
}
}
src, err := ref.NewImageSource(ctx, &m.image.runtime.systemContext)
if err != nil {
return err
}
defer src.Close()
subjectManifestBytes, subjectManifestType, err := src.GetManifest(ctx, nil)
if err != nil {
return err
}
subjectManifestDigest, err := manifest.Digest(subjectManifestBytes)
if err != nil {
return err
}
var subjectArtifactType string
if !manifest.MIMETypeIsMultiImage(subjectManifestType) {
var subjectManifest imgspecv1.Manifest
if json.Unmarshal(subjectManifestBytes, &subjectManifest) == nil {
subjectArtifactType = subjectManifest.ArtifactType
}
}
descriptor := &imgspecv1.Descriptor{
MediaType: subjectManifestType,
ArtifactType: subjectArtifactType,
Digest: subjectManifestDigest,
Size: int64(len(subjectManifestBytes)),
}
if err := m.list.SetSubject(descriptor); err != nil {
return err
}
}
// Write the changes to disk.
return m.saveAndReload()

View File

@ -711,10 +711,18 @@ func (l *list) AddArtifact(ctx context.Context, sys *types.SystemContext, option
if err != nil {
return "", fmt.Errorf("digesting manifest of subject %q: %w", transports.ImageName(options.SubjectReference), err)
}
var subjectArtifactType string
if !manifest.MIMETypeIsMultiImage(subjectManifestType) {
var subjectManifest v1.Manifest
if json.Unmarshal(subjectManifestBytes, &subjectManifest) == nil {
subjectArtifactType = subjectManifest.ArtifactType
}
}
subject = &v1.Descriptor{
MediaType: subjectManifestType,
Digest: subjectManifestDigest,
Size: int64(len(subjectManifestBytes)),
MediaType: subjectManifestType,
ArtifactType: subjectArtifactType,
Digest: subjectManifestDigest,
Size: int64(len(subjectManifestBytes)),
}
}

View File

@ -60,6 +60,23 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP
options = &PullOptions{}
}
defaultConfig, err := config.Default()
if err != nil {
return nil, err
}
if options.MaxRetries == nil {
options.MaxRetries = &defaultConfig.Engine.Retry
}
if options.RetryDelay == nil {
if defaultConfig.Engine.RetryDelay != "" {
duration, err := time.ParseDuration(defaultConfig.Engine.RetryDelay)
if err != nil {
return nil, fmt.Errorf("failed to parse containers.conf retry_delay: %w", err)
}
options.RetryDelay = &duration
}
}
var possiblyUnqualifiedName string // used for short-name resolution
ref, err := alltransports.ParseImageName(name)
if err != nil {

View File

@ -4,10 +4,14 @@ package libimage
import (
"context"
"fmt"
"time"
"github.com/containers/common/pkg/config"
dockerArchiveTransport "github.com/containers/image/v5/docker/archive"
dockerDaemonTransport "github.com/containers/image/v5/docker/daemon"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports/alltransports"
"github.com/sirupsen/logrus"
)
@ -31,6 +35,23 @@ func (r *Runtime) Push(ctx context.Context, source, destination string, options
options = &PushOptions{}
}
defaultConfig, err := config.Default()
if err != nil {
return nil, err
}
if options.MaxRetries == nil {
options.MaxRetries = &defaultConfig.Engine.Retry
}
if options.RetryDelay == nil {
if defaultConfig.Engine.RetryDelay != "" {
duration, err := time.ParseDuration(defaultConfig.Engine.RetryDelay)
if err != nil {
return nil, fmt.Errorf("failed to parse containers.conf retry_delay: %w", err)
}
options.RetryDelay = &duration
}
}
// Look up the local image. Note that we need to ignore the platform
// and push what the user specified (containers/podman/issues/10344).
image, resolvedSource, err := r.LookupImage(source, nil)
@ -65,6 +86,14 @@ func (r *Runtime) Push(ctx context.Context, source, destination string, options
destRef = dockerRef
}
// docker-archive and only DockerV2Schema2MediaType support Gzip compression
if options.CompressionFormat != nil &&
(destRef.Transport().Name() == dockerArchiveTransport.Transport.Name() ||
destRef.Transport().Name() == dockerDaemonTransport.Transport.Name() ||
options.ManifestMIMEType == manifest.DockerV2Schema2MediaType) {
options.CompressionFormat = nil
}
if r.eventChannel != nil {
defer r.writeEvent(&Event{ID: image.ID(), Name: destination, Time: time.Now(), Type: EventTypeImagePush})
}