diff --git a/define/build.go b/define/build.go index e3619955829..0a47712089e 100644 --- a/define/build.go +++ b/define/build.go @@ -4,6 +4,7 @@ import ( "io" "time" + "github.com/containers/common/libimage" nettypes "github.com/containers/common/libnetwork/types" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/types" @@ -272,6 +273,10 @@ type BuildOptions struct { // the build was unsuccessful. ForceRmIntermediateCtrs bool // BlobDirectory is a directory which we'll use for caching layer blobs. + // + // This option will be overridden for cache pulls if + // CachePullDestinationLookupReferenceFunc is set, and overridden for cache pushes if + // CachePushSourceLookupReferenceFunc is set. BlobDirectory string // Target the targeted FROM in the Dockerfile to build. Target string @@ -342,4 +347,23 @@ type BuildOptions struct { // CDIConfigDir is the location of CDI configuration files, if the files in // the default configuration locations shouldn't be used. CDIConfigDir string + // CachePullSourceLookupReferenceFunc is an optional LookupReferenceFunc + // used to look up source references for cache pulls. + CachePullSourceLookupReferenceFunc libimage.LookupReferenceFunc + // CachePullDestinationLookupReferenceFunc is an optional generator + // function which provides a LookupReferenceFunc used to look up + // destination references for cache pulls. + // + // BlobDirectory will be ignored for cache pulls if this option is set. + CachePullDestinationLookupReferenceFunc func(srcRef types.ImageReference) libimage.LookupReferenceFunc + // CachePushSourceLookupReferenceFunc is an optional generator function + // which provides a LookupReferenceFunc used to look up source + // references for cache pushes. + // + // BlobDirectory will be ignored for cache pushes if this option is set. + CachePushSourceLookupReferenceFunc func(dest types.ImageReference) libimage.LookupReferenceFunc + // CachePushDestinationLookupReferenceFunc is an optional + // LookupReferenceFunc used to look up destination references for cache + // pushes + CachePushDestinationLookupReferenceFunc libimage.LookupReferenceFunc } diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index ad5414a9a1e..b87d0493f1b 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -94,67 +94,71 @@ type Executor struct { cniPluginPath string cniConfigDir string // NetworkInterface is the libnetwork network interface used to setup CNI or netavark networks. - networkInterface nettypes.ContainerNetwork - idmappingOptions *define.IDMappingOptions - commonBuildOptions *define.CommonBuildOptions - defaultMountsFilePath string - iidfile string - squash bool - labels []string - layerLabels []string - annotations []string - layers bool - noHostname bool - noHosts bool - useCache bool - removeIntermediateCtrs bool - forceRmIntermediateCtrs bool - imageMap map[string]string // Used to map images that we create to handle the AS construct. - containerMap map[string]*buildah.Builder // Used to map from image names to only-created-for-the-rootfs containers. - baseMap map[string]struct{} // Holds the names of every base image, as given. - rootfsMap map[string]struct{} // Holds the names of every stage whose rootfs is referenced in a COPY or ADD instruction. - blobDirectory string - excludes []string - groupAdd []string - ignoreFile string - args map[string]string - globalArgs map[string]string - unusedArgs map[string]struct{} - capabilities []string - devices define.ContainerDevices - deviceSpecs []string - signBy string - architecture string - timestamp *time.Time - os string - maxPullPushRetries int - retryPullPushDelay time.Duration - ociDecryptConfig *encconfig.DecryptConfig - lastError error - terminatedStage map[string]error - stagesLock sync.Mutex - stagesSemaphore *semaphore.Weighted - logRusage bool - rusageLogFile io.Writer - imageInfoLock sync.Mutex - imageInfoCache map[string]imageTypeAndHistoryAndDiffIDs - fromOverride string - additionalBuildContexts map[string]*define.AdditionalBuildContext - manifest string - secrets map[string]define.Secret - sshsources map[string]*sshagent.Source - logPrefix string - unsetEnvs []string - unsetLabels []string - processLabel string // Shares processLabel of first stage container with containers of other stages in same build - mountLabel string // Shares mountLabel of first stage container with containers of other stages in same build - buildOutput string // Specifies instructions for any custom build output - osVersion string - osFeatures []string - envs []string - confidentialWorkload define.ConfidentialWorkloadOptions - sbomScanOptions []define.SBOMScanOptions - cdiConfigDir string + networkInterface nettypes.ContainerNetwork + idmappingOptions *define.IDMappingOptions + commonBuildOptions *define.CommonBuildOptions + defaultMountsFilePath string + iidfile string + squash bool + labels []string + layerLabels []string + annotations []string + layers bool + noHostname bool + noHosts bool + useCache bool + removeIntermediateCtrs bool + forceRmIntermediateCtrs bool + imageMap map[string]string // Used to map images that we create to handle the AS construct. + containerMap map[string]*buildah.Builder // Used to map from image names to only-created-for-the-rootfs containers. + baseMap map[string]struct{} // Holds the names of every base image, as given. + rootfsMap map[string]struct{} // Holds the names of every stage whose rootfs is referenced in a COPY or ADD instruction. + blobDirectory string + excludes []string + groupAdd []string + ignoreFile string + args map[string]string + globalArgs map[string]string + unusedArgs map[string]struct{} + capabilities []string + devices define.ContainerDevices + deviceSpecs []string + signBy string + architecture string + timestamp *time.Time + os string + maxPullPushRetries int + retryPullPushDelay time.Duration + cachePullSourceLookupReferenceFunc libimage.LookupReferenceFunc + cachePullDestinationLookupReferenceFunc func(srcRef types.ImageReference) libimage.LookupReferenceFunc + cachePushSourceLookupReferenceFunc func(dest types.ImageReference) libimage.LookupReferenceFunc + cachePushDestinationLookupReferenceFunc libimage.LookupReferenceFunc + ociDecryptConfig *encconfig.DecryptConfig + lastError error + terminatedStage map[string]error + stagesLock sync.Mutex + stagesSemaphore *semaphore.Weighted + logRusage bool + rusageLogFile io.Writer + imageInfoLock sync.Mutex + imageInfoCache map[string]imageTypeAndHistoryAndDiffIDs + fromOverride string + additionalBuildContexts map[string]*define.AdditionalBuildContext + manifest string + secrets map[string]define.Secret + sshsources map[string]*sshagent.Source + logPrefix string + unsetEnvs []string + unsetLabels []string + processLabel string // Shares processLabel of first stage container with containers of other stages in same build + mountLabel string // Shares mountLabel of first stage container with containers of other stages in same build + buildOutput string // Specifies instructions for any custom build output + osVersion string + osFeatures []string + envs []string + confidentialWorkload define.ConfidentialWorkloadOptions + sbomScanOptions []define.SBOMScanOptions + cdiConfigDir string } type imageTypeAndHistoryAndDiffIDs struct { @@ -221,92 +225,96 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o } exec := Executor{ - args: options.Args, - cacheFrom: options.CacheFrom, - cacheTo: options.CacheTo, - cacheTTL: options.CacheTTL, - containerSuffix: options.ContainerSuffix, - logger: logger, - stages: make(map[string]*StageExecutor), - store: store, - contextDir: options.ContextDirectory, - excludes: excludes, - groupAdd: options.GroupAdd, - ignoreFile: options.IgnoreFile, - pullPolicy: options.PullPolicy, - registry: options.Registry, - ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions, - quiet: options.Quiet, - runtime: options.Runtime, - runtimeArgs: options.RuntimeArgs, - transientMounts: transientMounts, - compression: options.Compression, - output: options.Output, - outputFormat: options.OutputFormat, - additionalTags: options.AdditionalTags, - signaturePolicyPath: options.SignaturePolicyPath, - skipUnusedStages: options.SkipUnusedStages, - systemContext: options.SystemContext, - log: options.Log, - in: options.In, - out: options.Out, - err: options.Err, - reportWriter: writer, - isolation: options.Isolation, - namespaceOptions: options.NamespaceOptions, - configureNetwork: options.ConfigureNetwork, - cniPluginPath: options.CNIPluginPath, - cniConfigDir: options.CNIConfigDir, - networkInterface: options.NetworkInterface, - idmappingOptions: options.IDMappingOptions, - commonBuildOptions: options.CommonBuildOpts, - defaultMountsFilePath: options.DefaultMountsFilePath, - iidfile: options.IIDFile, - squash: options.Squash, - labels: append([]string{}, options.Labels...), - layerLabels: append([]string{}, options.LayerLabels...), - annotations: append([]string{}, options.Annotations...), - layers: options.Layers, - noHostname: options.CommonBuildOpts.NoHostname, - noHosts: options.CommonBuildOpts.NoHosts, - useCache: !options.NoCache, - removeIntermediateCtrs: options.RemoveIntermediateCtrs, - forceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, - imageMap: make(map[string]string), - containerMap: make(map[string]*buildah.Builder), - baseMap: make(map[string]struct{}), - rootfsMap: make(map[string]struct{}), - blobDirectory: options.BlobDirectory, - unusedArgs: make(map[string]struct{}), - capabilities: capabilities, - deviceSpecs: options.Devices, - signBy: options.SignBy, - architecture: options.Architecture, - timestamp: options.Timestamp, - os: options.OS, - maxPullPushRetries: options.MaxPullPushRetries, - retryPullPushDelay: options.PullPushRetryDelay, - ociDecryptConfig: options.OciDecryptConfig, - terminatedStage: make(map[string]error), - stagesSemaphore: options.JobSemaphore, - logRusage: options.LogRusage, - rusageLogFile: rusageLogFile, - imageInfoCache: make(map[string]imageTypeAndHistoryAndDiffIDs), - fromOverride: options.From, - additionalBuildContexts: options.AdditionalBuildContexts, - manifest: options.Manifest, - secrets: secrets, - sshsources: sshsources, - logPrefix: logPrefix, - unsetEnvs: append([]string{}, options.UnsetEnvs...), - unsetLabels: append([]string{}, options.UnsetLabels...), - buildOutput: options.BuildOutput, - osVersion: options.OSVersion, - osFeatures: append([]string{}, options.OSFeatures...), - envs: append([]string{}, options.Envs...), - confidentialWorkload: options.ConfidentialWorkload, - sbomScanOptions: options.SBOMScanOptions, - cdiConfigDir: options.CDIConfigDir, + args: options.Args, + cacheFrom: options.CacheFrom, + cacheTo: options.CacheTo, + cacheTTL: options.CacheTTL, + containerSuffix: options.ContainerSuffix, + logger: logger, + stages: make(map[string]*StageExecutor), + store: store, + contextDir: options.ContextDirectory, + excludes: excludes, + groupAdd: options.GroupAdd, + ignoreFile: options.IgnoreFile, + pullPolicy: options.PullPolicy, + registry: options.Registry, + ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions, + quiet: options.Quiet, + runtime: options.Runtime, + runtimeArgs: options.RuntimeArgs, + transientMounts: transientMounts, + compression: options.Compression, + output: options.Output, + outputFormat: options.OutputFormat, + additionalTags: options.AdditionalTags, + signaturePolicyPath: options.SignaturePolicyPath, + skipUnusedStages: options.SkipUnusedStages, + systemContext: options.SystemContext, + log: options.Log, + in: options.In, + out: options.Out, + err: options.Err, + reportWriter: writer, + isolation: options.Isolation, + namespaceOptions: options.NamespaceOptions, + configureNetwork: options.ConfigureNetwork, + cniPluginPath: options.CNIPluginPath, + cniConfigDir: options.CNIConfigDir, + networkInterface: options.NetworkInterface, + idmappingOptions: options.IDMappingOptions, + commonBuildOptions: options.CommonBuildOpts, + defaultMountsFilePath: options.DefaultMountsFilePath, + iidfile: options.IIDFile, + squash: options.Squash, + labels: append([]string{}, options.Labels...), + layerLabels: append([]string{}, options.LayerLabels...), + annotations: append([]string{}, options.Annotations...), + layers: options.Layers, + noHostname: options.CommonBuildOpts.NoHostname, + noHosts: options.CommonBuildOpts.NoHosts, + useCache: !options.NoCache, + removeIntermediateCtrs: options.RemoveIntermediateCtrs, + forceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, + imageMap: make(map[string]string), + containerMap: make(map[string]*buildah.Builder), + baseMap: make(map[string]struct{}), + rootfsMap: make(map[string]struct{}), + blobDirectory: options.BlobDirectory, + unusedArgs: make(map[string]struct{}), + capabilities: capabilities, + deviceSpecs: options.Devices, + signBy: options.SignBy, + architecture: options.Architecture, + timestamp: options.Timestamp, + os: options.OS, + maxPullPushRetries: options.MaxPullPushRetries, + retryPullPushDelay: options.PullPushRetryDelay, + cachePullSourceLookupReferenceFunc: options.CachePullSourceLookupReferenceFunc, + cachePullDestinationLookupReferenceFunc: options.CachePullDestinationLookupReferenceFunc, + cachePushSourceLookupReferenceFunc: options.CachePushSourceLookupReferenceFunc, + cachePushDestinationLookupReferenceFunc: options.CachePushDestinationLookupReferenceFunc, + ociDecryptConfig: options.OciDecryptConfig, + terminatedStage: make(map[string]error), + stagesSemaphore: options.JobSemaphore, + logRusage: options.LogRusage, + rusageLogFile: rusageLogFile, + imageInfoCache: make(map[string]imageTypeAndHistoryAndDiffIDs), + fromOverride: options.From, + additionalBuildContexts: options.AdditionalBuildContexts, + manifest: options.Manifest, + secrets: secrets, + sshsources: sshsources, + logPrefix: logPrefix, + unsetEnvs: append([]string{}, options.UnsetEnvs...), + unsetLabels: append([]string{}, options.UnsetLabels...), + buildOutput: options.BuildOutput, + osVersion: options.OSVersion, + osFeatures: append([]string{}, options.OSFeatures...), + envs: append([]string{}, options.Envs...), + confidentialWorkload: options.ConfidentialWorkload, + sbomScanOptions: options.SBOMScanOptions, + cdiConfigDir: options.CDIConfigDir, } if exec.err == nil { exec.err = os.Stderr diff --git a/imagebuildah/stage_executor.go b/imagebuildah/stage_executor.go index 99aa3a0c751..bc004baae59 100644 --- a/imagebuildah/stage_executor.go +++ b/imagebuildah/stage_executor.go @@ -1992,6 +1992,12 @@ func (s *StageExecutor) pushCache(ctx context.Context, src, cacheKey string) err MaxRetries: s.executor.maxPullPushRetries, RetryDelay: s.executor.retryPullPushDelay, } + if s.executor.cachePushSourceLookupReferenceFunc != nil { + options.SourceLookupReferenceFunc = s.executor.cachePushSourceLookupReferenceFunc(dest) + } + if s.executor.cachePushDestinationLookupReferenceFunc != nil { + options.DestinationLookupReferenceFunc = s.executor.cachePushDestinationLookupReferenceFunc + } ref, digest, err := buildah.Push(ctx, src, dest, options) if err != nil { return fmt.Errorf("failed pushing cache to %q: %w", dest, err) @@ -2013,7 +2019,8 @@ func (s *StageExecutor) pullCache(ctx context.Context, cacheKey string) (referen return nil, "", err } for _, src := range srcList { - logrus.Debugf("trying to pull cache from remote repo: %+v", src.DockerReference()) + srcDockerRef := src.DockerReference() + logrus.Debugf("trying to pull cache from remote repo: %+v", srcDockerRef) options := buildah.PullOptions{ SignaturePolicyPath: s.executor.signaturePolicyPath, Store: s.executor.store, @@ -2025,7 +2032,14 @@ func (s *StageExecutor) pullCache(ctx context.Context, cacheKey string) (referen ReportWriter: nil, PullPolicy: define.PullIfNewer, } - id, err := buildah.Pull(ctx, src.DockerReference().String(), options) + if s.executor.cachePullSourceLookupReferenceFunc != nil { + options.SourceLookupReferenceFunc = s.executor.cachePullSourceLookupReferenceFunc + } + if s.executor.cachePullDestinationLookupReferenceFunc != nil { + options.DestinationLookupReferenceFunc = s.executor.cachePullDestinationLookupReferenceFunc(src) + } + + id, err := buildah.Pull(ctx, srcDockerRef.String(), options) if err != nil { logrus.Debugf("failed pulling cache from source %s: %v", src, err) continue // failed pulling this one try next diff --git a/pull.go b/pull.go index 343c61fba73..13c2bfbbc84 100644 --- a/pull.go +++ b/pull.go @@ -33,6 +33,8 @@ type PullOptions struct { // BlobDirectory is the name of a directory in which we'll attempt to // store copies of layer blobs that we pull down, if any. It should // already exist. + // + // Not applicable if DestinationLookupReferenceFunc is set. BlobDirectory string // AllTags is a boolean value that determines if all tagged images // will be downloaded from the repository. The default is false. @@ -50,6 +52,12 @@ type PullOptions struct { OciDecryptConfig *encconfig.DecryptConfig // PullPolicy takes the value PullIfMissing, PullAlways, PullIfNewer, or PullNever. PullPolicy define.PullPolicy + // SourceLookupReference provides a function to look up source + // references. + SourceLookupReferenceFunc libimage.LookupReferenceFunc + // DestinationLookupReference provides a function to look up destination + // references. Overrides BlobDirectory, if set. + DestinationLookupReferenceFunc libimage.LookupReferenceFunc } // Pull copies the contents of the image from somewhere else to local storage. Returns the @@ -62,7 +70,12 @@ func Pull(ctx context.Context, imageName string, options PullOptions) (imageID s libimageOptions.OciDecryptConfig = options.OciDecryptConfig libimageOptions.AllTags = options.AllTags libimageOptions.RetryDelay = &options.RetryDelay - libimageOptions.DestinationLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal) + libimageOptions.SourceLookupReferenceFunc = options.SourceLookupReferenceFunc + if options.DestinationLookupReferenceFunc != nil { + libimageOptions.DestinationLookupReferenceFunc = options.DestinationLookupReferenceFunc + } else { + libimageOptions.DestinationLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal) + } if options.MaxRetries > 0 { retries := uint(options.MaxRetries) diff --git a/push.go b/push.go index 2e2b9498ae4..9d9d7a88ba3 100644 --- a/push.go +++ b/push.go @@ -66,6 +66,8 @@ type PushOptions struct { // 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. + // + // Not applicable if SourceLookupReferenceFunc is set. BlobDirectory string // Quiet is a boolean value that determines if minimal output to // the user will be displayed, this is best used for logging. @@ -90,6 +92,12 @@ type PushOptions struct { // integers in the slice represent 0-indexed layer indices, with support for negative // indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer. OciEncryptLayers *[]int + // SourceLookupReference provides a function to look up source + // references. Overrides BlobDirectory, if set. + SourceLookupReferenceFunc libimage.LookupReferenceFunc + // DestinationLookupReference provides a function to look up destination + // references. + DestinationLookupReferenceFunc libimage.LookupReferenceFunc // CompressionFormat is the format to use for the compression of the blobs CompressionFormat *compression.Algorithm @@ -125,7 +133,12 @@ func Push(ctx context.Context, image string, dest types.ImageReference, options if options.Compression == archive.Gzip { compress = types.Compress } - libimageOptions.SourceLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, compress) + if options.SourceLookupReferenceFunc != nil { + libimageOptions.SourceLookupReferenceFunc = options.SourceLookupReferenceFunc + } else { + libimageOptions.SourceLookupReferenceFunc = cacheLookupReferenceFunc(options.BlobDirectory, compress) + } + libimageOptions.DestinationLookupReferenceFunc = options.DestinationLookupReferenceFunc runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext}) if err != nil {