| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | package buildah | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/containers/buildah/pkg/blobcache" | 
					
						
							|  |  |  | 	encconfig "github.com/containers/ocicrypt/config" | 
					
						
							|  |  |  | 	digest "github.com/opencontainers/go-digest" | 
					
						
							|  |  |  | 	"github.com/sirupsen/logrus" | 
					
						
							| 
									
										
										
										
											2025-08-29 20:55:12 +08:00
										 |  |  | 	"go.podman.io/common/libimage" | 
					
						
							|  |  |  | 	"go.podman.io/image/v5/docker/reference" | 
					
						
							|  |  |  | 	"go.podman.io/image/v5/manifest" | 
					
						
							|  |  |  | 	"go.podman.io/image/v5/pkg/compression" | 
					
						
							|  |  |  | 	"go.podman.io/image/v5/transports" | 
					
						
							|  |  |  | 	"go.podman.io/image/v5/types" | 
					
						
							|  |  |  | 	"go.podman.io/storage" | 
					
						
							|  |  |  | 	"go.podman.io/storage/pkg/archive" | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-22 21:24:48 +08:00
										 |  |  | // cacheLookupReferenceFunc wraps a BlobCache into a
 | 
					
						
							|  |  |  | // libimage.LookupReferenceFunc to allow for using a BlobCache during
 | 
					
						
							|  |  |  | // image-copy operations.
 | 
					
						
							|  |  |  | func cacheLookupReferenceFunc(directory string, compress types.LayerCompression) libimage.LookupReferenceFunc { | 
					
						
							|  |  |  | 	// Using a closure here allows us to reference a BlobCache without
 | 
					
						
							|  |  |  | 	// having to explicitly maintain it in the libimage API.
 | 
					
						
							|  |  |  | 	return func(ref types.ImageReference) (types.ImageReference, error) { | 
					
						
							|  |  |  | 		if directory == "" { | 
					
						
							|  |  |  | 			return ref, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ref, err := blobcache.NewBlobCache(ref, directory, compress) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 			return nil, fmt.Errorf("using blobcache %q: %w", directory, err) | 
					
						
							| 
									
										
										
										
											2022-02-22 21:24:48 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return ref, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | // PushOptions can be used to alter how an image is copied somewhere.
 | 
					
						
							|  |  |  | type PushOptions struct { | 
					
						
							|  |  |  | 	// Compression specifies the type of compression which is applied to
 | 
					
						
							|  |  |  | 	// layer blobs.  The default is to not use compression, but
 | 
					
						
							|  |  |  | 	// archive.Gzip is recommended.
 | 
					
						
							| 
									
										
										
										
											2021-09-22 23:34:16 +08:00
										 |  |  | 	// OBSOLETE: Use CompressionFormat instead.
 | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 	Compression archive.Compression | 
					
						
							|  |  |  | 	// SignaturePolicyPath specifies an override location for the signature
 | 
					
						
							|  |  |  | 	// policy which should be used for verifying the new image as it is
 | 
					
						
							|  |  |  | 	// being written.  Except in specific circumstances, no value should be
 | 
					
						
							|  |  |  | 	// specified, indicating that the shared, system-wide default policy
 | 
					
						
							|  |  |  | 	// should be used.
 | 
					
						
							|  |  |  | 	SignaturePolicyPath string | 
					
						
							|  |  |  | 	// ReportWriter is an io.Writer which will be used to log the writing
 | 
					
						
							|  |  |  | 	// of the new image.
 | 
					
						
							|  |  |  | 	ReportWriter io.Writer | 
					
						
							|  |  |  | 	// Store is the local storage store which holds the source image.
 | 
					
						
							|  |  |  | 	Store storage.Store | 
					
						
							|  |  |  | 	// github.com/containers/image/types SystemContext to hold credentials
 | 
					
						
							|  |  |  | 	// and other authentication/authorization information.
 | 
					
						
							|  |  |  | 	SystemContext *types.SystemContext | 
					
						
							| 
									
										
										
										
											2021-06-18 01:38:49 +08:00
										 |  |  | 	// ManifestType is the format to use
 | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 	// possible options are oci, v2s1, and v2s2
 | 
					
						
							|  |  |  | 	ManifestType string | 
					
						
							|  |  |  | 	// BlobDirectory is the name of a directory in which we'll look for
 | 
					
						
							|  |  |  | 	// prebuilt copies of layer blobs that we might otherwise need to
 | 
					
						
							|  |  |  | 	// regenerate from on-disk layers, substituting them in the list of
 | 
					
						
							|  |  |  | 	// blobs to copy whenever possible.
 | 
					
						
							| 
									
										
										
										
											2024-05-28 00:48:41 +08:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// Not applicable if SourceLookupReferenceFunc is set.
 | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 	BlobDirectory string | 
					
						
							|  |  |  | 	// Quiet is a boolean value that determines if minimal output to
 | 
					
						
							|  |  |  | 	// the user will be displayed, this is best used for logging.
 | 
					
						
							|  |  |  | 	// The default is false.
 | 
					
						
							|  |  |  | 	Quiet bool | 
					
						
							|  |  |  | 	// SignBy is the fingerprint of a GPG key to use for signing the image.
 | 
					
						
							|  |  |  | 	SignBy string | 
					
						
							|  |  |  | 	// RemoveSignatures causes any existing signatures for the image to be
 | 
					
						
							|  |  |  | 	// discarded for the pushed copy.
 | 
					
						
							|  |  |  | 	RemoveSignatures bool | 
					
						
							|  |  |  | 	// MaxRetries is the maximum number of attempts we'll make to push any
 | 
					
						
							|  |  |  | 	// one image to the external registry if the first attempt fails.
 | 
					
						
							|  |  |  | 	MaxRetries int | 
					
						
							|  |  |  | 	// RetryDelay is how long to wait before retrying a push attempt.
 | 
					
						
							|  |  |  | 	RetryDelay time.Duration | 
					
						
							|  |  |  | 	// OciEncryptConfig when non-nil indicates that an image should be encrypted.
 | 
					
						
							|  |  |  | 	// The encryption options is derived from the construction of EncryptConfig object.
 | 
					
						
							|  |  |  | 	OciEncryptConfig *encconfig.EncryptConfig | 
					
						
							|  |  |  | 	// OciEncryptLayers represents the list of layers to encrypt.
 | 
					
						
							|  |  |  | 	// If nil, don't encrypt any layers.
 | 
					
						
							|  |  |  | 	// If non-nil and len==0, denotes encrypt all layers.
 | 
					
						
							| 
									
										
										
										
											2021-05-06 03:56:00 +08:00
										 |  |  | 	// integers in the slice represent 0-indexed layer indices, with support for negative
 | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 	// indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
 | 
					
						
							|  |  |  | 	OciEncryptLayers *[]int | 
					
						
							| 
									
										
										
										
											2024-05-16 23:41:16 +08:00
										 |  |  | 	// SourceLookupReference provides a function to look up source
 | 
					
						
							| 
									
										
										
										
											2024-05-28 00:48:41 +08:00
										 |  |  | 	// references. Overrides BlobDirectory, if set.
 | 
					
						
							| 
									
										
										
										
											2024-05-16 23:41:16 +08:00
										 |  |  | 	SourceLookupReferenceFunc libimage.LookupReferenceFunc | 
					
						
							|  |  |  | 	// DestinationLookupReference provides a function to look up destination
 | 
					
						
							|  |  |  | 	// references.
 | 
					
						
							|  |  |  | 	DestinationLookupReferenceFunc libimage.LookupReferenceFunc | 
					
						
							| 
									
										
										
										
											2021-09-22 23:34:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// CompressionFormat is the format to use for the compression of the blobs
 | 
					
						
							|  |  |  | 	CompressionFormat *compression.Algorithm | 
					
						
							|  |  |  | 	// CompressionLevel specifies what compression level is used
 | 
					
						
							|  |  |  | 	CompressionLevel *int | 
					
						
							| 
									
										
										
										
											2023-08-12 02:17:11 +08:00
										 |  |  | 	// ForceCompressionFormat ensures that the compression algorithm set in
 | 
					
						
							|  |  |  | 	// CompressionFormat is used exclusively, and blobs of other compression
 | 
					
						
							|  |  |  | 	// algorithms are not reused.
 | 
					
						
							|  |  |  | 	ForceCompressionFormat bool | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Push copies the contents of the image to a new location.
 | 
					
						
							|  |  |  | func Push(ctx context.Context, image string, dest types.ImageReference, options PushOptions) (reference.Canonical, digest.Digest, error) { | 
					
						
							|  |  |  | 	libimageOptions := &libimage.PushOptions{} | 
					
						
							|  |  |  | 	libimageOptions.SignaturePolicyPath = options.SignaturePolicyPath | 
					
						
							|  |  |  | 	libimageOptions.Writer = options.ReportWriter | 
					
						
							|  |  |  | 	libimageOptions.ManifestMIMEType = options.ManifestType | 
					
						
							|  |  |  | 	libimageOptions.SignBy = options.SignBy | 
					
						
							|  |  |  | 	libimageOptions.RemoveSignatures = options.RemoveSignatures | 
					
						
							|  |  |  | 	libimageOptions.RetryDelay = &options.RetryDelay | 
					
						
							|  |  |  | 	libimageOptions.OciEncryptConfig = options.OciEncryptConfig | 
					
						
							|  |  |  | 	libimageOptions.OciEncryptLayers = options.OciEncryptLayers | 
					
						
							| 
									
										
										
										
											2021-09-22 23:34:16 +08:00
										 |  |  | 	libimageOptions.CompressionFormat = options.CompressionFormat | 
					
						
							|  |  |  | 	libimageOptions.CompressionLevel = options.CompressionLevel | 
					
						
							| 
									
										
										
										
											2023-08-12 02:17:11 +08:00
										 |  |  | 	libimageOptions.ForceCompressionFormat = options.ForceCompressionFormat | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 	libimageOptions.PolicyAllowStorage = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if options.Quiet { | 
					
						
							|  |  |  | 		libimageOptions.Writer = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-22 21:24:48 +08:00
										 |  |  | 	compress := types.PreserveOriginal | 
					
						
							|  |  |  | 	if options.Compression == archive.Gzip { | 
					
						
							|  |  |  | 		compress = types.Compress | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-16 23:41:16 +08:00
										 |  |  | 	if options.SourceLookupReferenceFunc != nil { | 
					
						
							|  |  |  | 		libimageOptions.SourceLookupReferenceFunc = options.SourceLookupReferenceFunc | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		libimageOptions.SourceLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, compress) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	libimageOptions.DestinationLookupReferenceFunc = options.DestinationLookupReferenceFunc | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	destString := fmt.Sprintf("%s:%s", dest.Transport().Name(), dest.StringWithinTransport()) | 
					
						
							|  |  |  | 	manifestBytes, err := runtime.Push(ctx, image, destString, libimageOptions) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	manifestDigest, err := manifest.Digest(manifestBytes) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-09-18 18:36:08 +08:00
										 |  |  | 		return nil, "", fmt.Errorf("computing digest of manifest of new image %q: %w", transports.ImageName(dest), err) | 
					
						
							| 
									
										
										
										
											2021-04-23 16:26:26 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ref reference.Canonical | 
					
						
							|  |  |  | 	if name := dest.DockerReference(); name != nil { | 
					
						
							|  |  |  | 		ref, err = reference.WithDigest(name, manifestDigest) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			logrus.Warnf("error generating canonical reference with name %q and digest %s: %v", name, manifestDigest.String(), err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ref, manifestDigest, nil | 
					
						
							|  |  |  | } |