restore push/pull and util API

Restore the push and pull API that commit dcd2a92e56 removed.
These changes would break vendoring into openshift/builder due
to build errors.

For the same reason, restore `util.FindImage` and `util.AddImageNames`
but deprecate the `findRegistry` argument.

Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
Valentin Rothberg 2021-04-23 10:26:26 +02:00
parent eb52311c23
commit fb331c1861
10 changed files with 375 additions and 146 deletions

View File

@ -235,7 +235,7 @@ func manifestCreateCmd(c *cobra.Command, args []string, opts manifestCreateOpts)
if err != nil {
if ref, err = alltransports.ParseImageName(util.DefaultTransport + imageSpec); err != nil {
// check if the local image exists
if ref, _, err = util.FindImage(store, systemContext, imageSpec); err != nil {
if ref, _, err = util.FindImage(store, "", systemContext, imageSpec); err != nil {
return err
}
}
@ -285,7 +285,7 @@ func manifestAddCmd(c *cobra.Command, args []string, opts manifestAddOpts) error
return errors.Wrapf(err, "error building system context")
}
_, listImage, err := util.FindImage(store, systemContext, listImageSpec)
_, listImage, err := util.FindImage(store, "", systemContext, listImageSpec)
if err != nil {
return err
}
@ -294,7 +294,7 @@ func manifestAddCmd(c *cobra.Command, args []string, opts manifestAddOpts) error
if err != nil {
if ref, err = alltransports.ParseImageName(util.DefaultTransport + imageSpec); err != nil {
// check if the local image exists
if ref, _, err = util.FindImage(store, systemContext, imageSpec); err != nil {
if ref, _, err = util.FindImage(store, "", systemContext, imageSpec); err != nil {
return err
}
}
@ -309,7 +309,7 @@ func manifestAddCmd(c *cobra.Command, args []string, opts manifestAddOpts) error
if err != nil {
var storeErr error
// check if the local image exists
if ref, _, storeErr = util.FindImage(store, systemContext, imageSpec); storeErr != nil {
if ref, _, storeErr = util.FindImage(store, "", systemContext, imageSpec); storeErr != nil {
return err
}
digest, storeErr = list.Add(getContext(), systemContext, ref, opts.all)
@ -404,7 +404,7 @@ func manifestRemoveCmd(c *cobra.Command, args []string, opts manifestRemoveOpts)
return errors.Wrapf(err, "error building system context")
}
_, listImage, err := util.FindImage(store, systemContext, listImageSpec)
_, listImage, err := util.FindImage(store, "", systemContext, listImageSpec)
if err != nil {
return err
}
@ -461,7 +461,7 @@ func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateO
return errors.Wrapf(err, "error building system context")
}
_, listImage, err := util.FindImage(store, systemContext, listImageSpec)
_, listImage, err := util.FindImage(store, "", systemContext, listImageSpec)
if err != nil {
return err
}
@ -474,7 +474,7 @@ func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateO
digest, err := digest.Parse(imageSpec)
if err != nil {
ctx := getContext()
ref, _, err := util.FindImage(store, systemContext, imageSpec)
ref, _, err := util.FindImage(store, "", systemContext, imageSpec)
if err != nil {
return err
}
@ -581,7 +581,7 @@ func manifestInspect(ctx context.Context, store storage.Store, systemContext *ty
logrus.Debugf("error parsing reference to image %q: %v", imageSpec, err)
}
if ref, _, err := util.FindImage(store, systemContext, imageSpec); err == nil {
if ref, _, err := util.FindImage(store, "", systemContext, imageSpec); err == nil {
refs = append(refs, ref)
} else if ref, err := alltransports.ParseImageName(imageSpec); err == nil {
refs = append(refs, ref)
@ -679,7 +679,7 @@ func manifestPushCmd(c *cobra.Command, args []string, opts pushOptions) error {
}
func manifestPush(systemContext *types.SystemContext, store storage.Store, listImageSpec, destSpec string, opts pushOptions) error {
_, listImage, err := util.FindImage(store, systemContext, listImageSpec)
_, listImage, err := util.FindImage(store, "", systemContext, listImageSpec)
if err != nil {
return err
}

View File

@ -1,32 +1,31 @@
package main
import (
"context"
"fmt"
"os"
"runtime"
"github.com/containers/buildah/pkg/blobcache"
"github.com/containers/buildah"
"github.com/containers/buildah/define"
buildahcli "github.com/containers/buildah/pkg/cli"
"github.com/containers/buildah/pkg/parse"
"github.com/containers/common/libimage"
libimageTypes "github.com/containers/common/libimage/types"
"github.com/containers/common/pkg/auth"
"github.com/containers/image/v5/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type pullOptions struct {
// We can feed many flags directly to the options of libmage.
libimage.PullOptions
// Other flags need some massaging and validation.
allTags bool
authfile string
blobCache string
pullPolicy string
decryptionKeys []string
tlsVerify bool
certDir string
creds string
signaturePolicy string
quiet bool
removeSignatures bool
tlsVerify bool
decryptionKeys []string
pullPolicy string
}
func init() {
@ -43,7 +42,7 @@ func init() {
Short: "Pull an image from the specified location",
Long: pullDescription,
RunE: func(cmd *cobra.Command, args []string) error {
return pullCmd(cmd, args, &opts)
return pullCmd(cmd, args, opts)
},
Example: `buildah pull imagename
buildah pull docker-daemon:imagename:imagetag
@ -53,22 +52,22 @@ func init() {
flags := pullCommand.Flags()
flags.SetInterspersed(false)
flags.BoolVarP(&opts.AllTags, "all-tags", "a", false, "download all tagged images in the repository")
flags.StringVar(&opts.AuthFilePath, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.BoolVarP(&opts.allTags, "all-tags", "a", false, "download all tagged images in the repository")
flags.StringVar(&opts.authfile, "authfile", auth.GetDefaultAuthFile(), "path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
flags.StringVar(&opts.blobCache, "blob-cache", "", "store copies of pulled image blobs in the specified directory")
flags.StringVar(&opts.CertDirPath, "cert-dir", "", "use certificates at the specified path to access the registry")
flags.StringVar(&opts.Credentials, "creds", "", "use `[username[:password]]` for accessing the registry")
flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry")
flags.StringVar(&opts.creds, "creds", "", "use `[username[:password]]` for accessing the registry")
flags.StringVar(&opts.pullPolicy, "policy", "missing", "missing, always, or never.")
flags.BoolVarP(&opts.RemoveSignatures, "remove-signatures", "", false, "don't copy signatures when pulling image")
flags.StringVar(&opts.SignaturePolicyPath, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
flags.BoolVarP(&opts.removeSignatures, "remove-signatures", "", false, "don't copy signatures when pulling image")
flags.StringVar(&opts.signaturePolicy, "signature-policy", "", "`pathname` of signature policy file (not usually used)")
flags.StringSliceVar(&opts.decryptionKeys, "decryption-key", nil, "key needed to decrypt the image")
if err := flags.MarkHidden("signature-policy"); err != nil {
panic(fmt.Sprintf("error marking signature-policy as hidden: %v", err))
}
flags.BoolVarP(&opts.quiet, "quiet", "q", false, "don't output progress information when pulling images")
flags.StringVar(&opts.OS, "os", runtime.GOOS, "prefer `OS` instead of the running OS for choosing images")
flags.StringVar(&opts.Architecture, "arch", runtime.GOARCH, "prefer `ARCH` instead of the architecture of the machine for choosing images")
flags.StringVar(&opts.Variant, "variant", "", "override the `variant` of the specified image")
flags.String("os", runtime.GOOS, "prefer `OS` instead of the running OS for choosing images")
flags.String("arch", runtime.GOARCH, "prefer `ARCH` instead of the architecture of the machine for choosing images")
flags.String("variant", "", "override the `variant` of the specified image")
flags.BoolVar(&opts.tlsVerify, "tls-verify", true, "require HTTPS and verify certificates when accessing the registry. TLS verification cannot be used when talking to an insecure registry.")
if err := flags.MarkHidden("blob-cache"); err != nil {
panic(fmt.Sprintf("error marking blob-cache as hidden: %v", err))
@ -77,8 +76,7 @@ func init() {
rootCmd.AddCommand(pullCommand)
}
func pullCmd(c *cobra.Command, args []string, options *pullOptions) error {
var err error
func pullCmd(c *cobra.Command, args []string, iopts pullOptions) error {
if len(args) == 0 {
return errors.Errorf("an image name must be specified")
}
@ -88,27 +86,7 @@ func pullCmd(c *cobra.Command, args []string, options *pullOptions) error {
if len(args) > 1 {
return errors.Errorf("too many arguments specified")
}
if err := auth.CheckAuthFile(options.AuthFilePath); err != nil {
return err
}
options.OciDecryptConfig, err = getDecryptConfig(options.decryptionKeys)
if err != nil {
return errors.Wrapf(err, "unable to obtain decrypt config")
}
options.Writer = os.Stderr
if options.quiet {
options.Writer = nil
}
if options.blobCache != "" {
// options.SourceLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.blobCache, types.PreserveOriginal)
options.DestinationLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.blobCache, types.PreserveOriginal)
}
pullPolicy, err := libimageTypes.ParsePullPolicy(options.pullPolicy)
if err != nil {
if err := auth.CheckAuthFile(iopts.authfile); err != nil {
return err
}
@ -122,19 +100,37 @@ func pullCmd(c *cobra.Command, args []string, options *pullOptions) error {
return err
}
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext})
decConfig, err := getDecryptConfig(iopts.decryptionKeys)
if err != nil {
return errors.Wrapf(err, "unable to obtain decrypt config")
}
policy, ok := define.PolicyMap[iopts.pullPolicy]
if !ok {
return fmt.Errorf("unsupported pull policy %q", iopts.pullPolicy)
}
options := buildah.PullOptions{
SignaturePolicyPath: iopts.signaturePolicy,
Store: store,
SystemContext: systemContext,
BlobDirectory: iopts.blobCache,
AllTags: iopts.allTags,
ReportWriter: os.Stderr,
RemoveSignatures: iopts.removeSignatures,
MaxRetries: maxPullPushRetries,
RetryDelay: pullPushRetryDelay,
OciDecryptConfig: decConfig,
PullPolicy: policy,
}
if iopts.quiet {
options.ReportWriter = nil // Turns off logging output
}
id, err := buildah.Pull(getContext(), args[0], options)
if err != nil {
return err
}
pulledImages, err := runtime.Pull(context.Background(), args[0], pullPolicy, &options.PullOptions)
if err != nil {
return err
}
for _, pulledImage := range pulledImages {
fmt.Printf("%s\n", pulledImage.ID())
}
fmt.Printf("%s\n", id)
return nil
}

View File

@ -1,20 +1,20 @@
package main
import (
"context"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/containers/buildah/pkg/blobcache"
"github.com/containers/buildah"
"github.com/containers/buildah/define"
buildahcli "github.com/containers/buildah/pkg/cli"
"github.com/containers/buildah/pkg/parse"
"github.com/containers/common/libimage"
"github.com/containers/buildah/util"
"github.com/containers/common/pkg/auth"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/types"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/storage"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@ -41,55 +41,6 @@ type pushOptions struct {
encryptLayers []int
}
// translates the pushOptions into libimage.PushOptions.
func (iopts *pushOptions) toLibimagePushOptions() (*libimage.PushOptions, error) {
pushOptions := &libimage.PushOptions{}
pushOptions.PolicyAllowStorage = true
pushOptions.AuthFilePath = iopts.authfile
pushOptions.CertDirPath = iopts.certDir
pushOptions.Credentials = iopts.creds
pushOptions.RemoveSignatures = iopts.removeSignatures
pushOptions.SignaturePolicyPath = iopts.signaturePolicy
pushOptions.SignBy = iopts.signBy
if iopts.blobCache != "" {
compress := types.Compress
if iopts.disableCompression {
compress = types.PreserveOriginal
}
pushOptions.SourceLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(iopts.blobCache, compress)
}
var manifestType string
if iopts.format != "" {
switch iopts.format {
case "oci":
manifestType = imgspecv1.MediaTypeImageManifest
case "v2s1":
manifestType = manifest.DockerV2Schema1SignedMediaType
case "v2s2", "docker":
manifestType = manifest.DockerV2Schema2MediaType
default:
return nil, errors.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", iopts.format)
}
}
pushOptions.ManifestMIMEType = manifestType
encConfig, encLayers, err := getEncryptConfig(iopts.encryptionKeys, iopts.encryptLayers)
if err != nil {
return nil, errors.Wrapf(err, "unable to obtain encryption config")
}
pushOptions.OciEncryptConfig = encConfig
pushOptions.OciEncryptLayers = encLayers
pushOptions.InsecureSkipTLSVerify = types.NewOptionalBool(!iopts.tlsVerify)
if !iopts.quiet {
pushOptions.Writer = os.Stderr
}
return pushOptions, nil
}
func init() {
var (
opts pushOptions
@ -174,52 +125,108 @@ func pushCmd(c *cobra.Command, args []string, iopts pushOptions) error {
return errors.New("Only two arguments are necessary to push: source and destination")
}
compress := define.Gzip
if iopts.disableCompression {
compress = define.Uncompressed
}
store, err := getStore(c)
if err != nil {
return err
}
dest, err := alltransports.ParseImageName(destSpec)
// add the docker:// transport to see if they neglected it.
if err != nil {
destTransport := strings.Split(destSpec, ":")[0]
if t := transports.Get(destTransport); t != nil {
return err
}
if strings.Contains(destSpec, "://") {
return err
}
destSpec = "docker://" + destSpec
dest2, err2 := alltransports.ParseImageName(destSpec)
if err2 != nil {
return err
}
dest = dest2
logrus.Debugf("Assuming docker:// as the transport method for DESTINATION: %s", destSpec)
}
systemContext, err := parse.SystemContextFromOptions(c)
if err != nil {
return errors.Wrapf(err, "error building system context")
}
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext})
if err != nil {
return err
var manifestType string
if iopts.format != "" {
switch iopts.format {
case "oci":
manifestType = imgspecv1.MediaTypeImageManifest
case "v2s1":
manifestType = manifest.DockerV2Schema1SignedMediaType
case "v2s2", "docker":
manifestType = manifest.DockerV2Schema2MediaType
default:
return errors.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", iopts.format)
}
}
pushOptions, err := iopts.toLibimagePushOptions()
encConfig, encLayers, err := getEncryptConfig(iopts.encryptionKeys, iopts.encryptLayers)
if err != nil {
return err
return errors.Wrapf(err, "unable to obtain encryption config")
}
pushedManifestBytes, pushError := runtime.Push(context.Background(), src, destSpec, pushOptions)
if pushError != nil {
// TODO: maybe we find a way to handle that transparently in libimage?
if errors.Cause(pushError) != storage.ErrImageUnknown {
options := buildah.PushOptions{
Compression: compress,
ManifestType: manifestType,
SignaturePolicyPath: iopts.signaturePolicy,
Store: store,
SystemContext: systemContext,
BlobDirectory: iopts.blobCache,
RemoveSignatures: iopts.removeSignatures,
SignBy: iopts.signBy,
MaxRetries: maxPullPushRetries,
RetryDelay: pullPushRetryDelay,
OciEncryptConfig: encConfig,
OciEncryptLayers: encLayers,
}
if !iopts.quiet {
options.ReportWriter = os.Stderr
}
ref, digest, err := buildah.Push(getContext(), src, dest, options)
if err != nil {
if errors.Cause(err) != storage.ErrImageUnknown {
// Image might be a manifest so attempt a manifest push
if manifestsErr := manifestPush(systemContext, store, src, destSpec, iopts); manifestsErr == nil {
return nil
}
}
return pushError
return util.GetFailureCause(err, errors.Wrapf(err, "error pushing image %q to %q", src, destSpec))
}
if ref != nil {
logrus.Debugf("pushed image %q with digest %s", ref, digest.String())
} else {
logrus.Debugf("pushed image with digest %s", digest.String())
}
logrus.Debugf("Successfully pushed %s with digest %s", transports.ImageName(dest), digest.String())
if iopts.digestfile != "" {
manifestDigest, err := manifest.Digest(pushedManifestBytes)
if err != nil {
return err
}
if err := ioutil.WriteFile(iopts.digestfile, []byte(manifestDigest.String()), 0644); err != nil {
return err
if err = ioutil.WriteFile(iopts.digestfile, []byte(digest.String()), 0644); err != nil {
return util.GetFailureCause(err, errors.Wrapf(err, "failed to write digest to file %q", iopts.digestfile))
}
}
return nil
}
// getListOfTransports gets the transports supported from the image library
// and strips of the "tarball" transport from the string of transports returned
func getListOfTransports() string {
allTransports := strings.Join(transports.ListNames(), ",")
return strings.Replace(allTransports, ",tarball", "", 1)

View File

@ -174,7 +174,7 @@ func (b *Builder) addManifest(ctx context.Context, manifestName string, imageSpe
var create bool
systemContext := &types.SystemContext{}
var list manifests.List
_, listImage, err := util.FindImage(b.store, systemContext, manifestName)
_, listImage, err := util.FindImage(b.store, "", systemContext, manifestName)
if err != nil {
create = true
list = manifests.Create()
@ -194,7 +194,7 @@ func (b *Builder) addManifest(ctx context.Context, manifestName string, imageSpe
if err != nil {
if ref, err = alltransports.ParseImageName(util.DefaultTransport + imageSpec); err != nil {
// check if the local image exists
if ref, _, err = util.FindImage(b.store, systemContext, imageSpec); err != nil {
if ref, _, err = util.FindImage(b.store, "", systemContext, imageSpec); err != nil {
return "", err
}
}
@ -355,7 +355,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options
if err != nil {
return imgID, nil, "", errors.Wrapf(err, "error locating just-written image %q", transports.ImageName(dest))
}
if err = util.TagImage(b.store, systemContext, img, options.AdditionalTags); err != nil {
if err = util.AddImageNames(b.store, "", systemContext, img, options.AdditionalTags); err != nil {
return imgID, nil, "", errors.Wrapf(err, "error setting image names to %v", append(img.Names, options.AdditionalTags...))
}
logrus.Debugf("assigned names %v to image %q", img.Names, img.ID)

View File

@ -684,7 +684,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image
return imageID, ref, errors.Wrapf(err, "error locating just-written image %q", transports.ImageName(dest))
}
if len(b.additionalTags) > 0 {
if err = util.TagImage(b.store, b.systemContext, img, b.additionalTags); err != nil {
if err = util.AddImageNames(b.store, "", b.systemContext, img, b.additionalTags); err != nil {
return imageID, ref, errors.Wrapf(err, "error setting image names to %v", append(img.Names, b.additionalTags...))
}
logrus.Debugf("assigned names %v to image %q", img.Names, img.ID)

View File

@ -153,7 +153,7 @@ func importBuilderFromImage(ctx context.Context, store storage.Store, options Im
systemContext := getSystemContext(store, options.SystemContext, options.SignaturePolicyPath)
_, img, err := util.FindImage(store, systemContext, options.Image)
_, img, err := util.FindImage(store, "", systemContext, options.Image)
if err != nil {
return nil, errors.Wrapf(err, "importing settings")
}

96
pull.go Normal file
View File

@ -0,0 +1,96 @@
package buildah
import (
"context"
"io"
"time"
"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/image/v5/types"
encconfig "github.com/containers/ocicrypt/config"
"github.com/containers/storage"
"github.com/pkg/errors"
)
// PullOptions can be used to alter how an image is copied in from somewhere.
type PullOptions struct {
// 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
// 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.
BlobDirectory string
// AllTags is a boolean value that determines if all tagged images
// will be downloaded from the repository. The default is false.
AllTags bool
// RemoveSignatures causes any existing signatures for the image to be
// discarded when pulling it.
RemoveSignatures bool
// MaxRetries is the maximum number of attempts we'll make to pull any
// one image from the external registry if the first attempt fails.
MaxRetries int
// RetryDelay is how long to wait before retrying a pull attempt.
RetryDelay time.Duration
// OciDecryptConfig contains the config that can be used to decrypt an image if it is
// encrypted if non-nil. If nil, it does not attempt to decrypt an image.
OciDecryptConfig *encconfig.DecryptConfig
// PullPolicy takes the value PullIfMissing, PullAlways, PullIfNewer, or PullNever.
PullPolicy define.PullPolicy
}
// Pull copies the contents of the image from somewhere else to local storage. Returns the
// ID of the local image or an error.
func Pull(ctx context.Context, imageName string, options PullOptions) (imageID string, err error) {
libimageOptions := &libimage.PullOptions{}
libimageOptions.SignaturePolicyPath = options.SignaturePolicyPath
libimageOptions.Writer = options.ReportWriter
libimageOptions.RemoveSignatures = options.RemoveSignatures
libimageOptions.OciDecryptConfig = options.OciDecryptConfig
libimageOptions.AllTags = options.AllTags
libimageOptions.RetryDelay = &options.RetryDelay
if options.MaxRetries > 0 {
retries := uint(options.MaxRetries)
libimageOptions.MaxRetries = &retries
}
if options.BlobDirectory != "" {
libimageOptions.DestinationLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.BlobDirectory, types.PreserveOriginal)
}
pullPolicy, err := libimageTypes.ParsePullPolicy(options.PullPolicy.String())
if err != nil {
return "", err
}
runtime, err := libimage.RuntimeFromStore(options.Store, &libimage.RuntimeOptions{SystemContext: options.SystemContext})
if err != nil {
return "", err
}
pulledImages, err := runtime.Pull(context.Background(), imageName, pullPolicy, libimageOptions)
if err != nil {
return "", err
}
if len(pulledImages) == 0 {
return "", errors.Errorf("internal error pulling %s: no image pulled and no error", imageName)
}
return pulledImages[0].ID(), nil
}

126
push.go Normal file
View File

@ -0,0 +1,126 @@
package buildah
import (
"context"
"fmt"
"io"
"time"
"github.com/containers/buildah/pkg/blobcache"
"github.com/containers/common/libimage"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/types"
encconfig "github.com/containers/ocicrypt/config"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
// 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.
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
// ManifestType is the format to use when saving the image using the 'dir' transport
// 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.
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.
// integers in the slice represent 0-indexed layer indices, with support for negativ
// indexing. i.e. 0 is the first layer, -1 is the last (top-most) layer.
OciEncryptLayers *[]int
}
// 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
libimageOptions.PolicyAllowStorage = true
if options.Quiet {
libimageOptions.Writer = nil
}
if options.BlobDirectory != "" {
compress := types.PreserveOriginal
if options.Compression == archive.Gzip {
compress = types.Compress
}
libimageOptions.SourceLookupReferenceFunc = blobcache.CacheLookupReferenceFunc(options.BlobDirectory, compress)
}
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 {
return nil, "", errors.Wrapf(err, "error computing digest of manifest of new image %q", transports.ImageName(dest))
}
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
}

View File

@ -105,7 +105,7 @@ func main() {
manifestType := ""
configType := ""
ref, _, err := util.FindImage(store, systemContext, image)
ref, _, err := util.FindImage(store, "", systemContext, image)
if err != nil {
ref2, err2 := alltransports.ParseImageName(image)
if err2 != nil {

View File

@ -161,7 +161,9 @@ func ExpandNames(names []string, systemContext *types.SystemContext, store stora
}
// FindImage locates the locally-stored image which corresponds to a given name.
func FindImage(store storage.Store, systemContext *types.SystemContext, image string) (types.ImageReference, *storage.Image, error) {
// Please note that the `firstRegistry` argument has been deprecated and has no
// effect anymore.
func FindImage(store storage.Store, firstRegistry string, systemContext *types.SystemContext, image string) (types.ImageReference, *storage.Image, error) {
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext})
if err != nil {
return nil, nil, err
@ -212,8 +214,10 @@ func ResolveNameToReferences(
return refs, nil
}
// TagImage adds the specified names to the specified image.
func TagImage(store storage.Store, systemContext *types.SystemContext, image *storage.Image, addNames []string) error {
// AddImageNames adds the specified names to the specified image. Please note
// that the `firstRegistry` argument has been deprecated and has no effect
// anymore.
func AddImageNames(store storage.Store, firstRegistry string, systemContext *types.SystemContext, image *storage.Image, addNames []string) error {
runtime, err := libimage.RuntimeFromStore(store, &libimage.RuntimeOptions{SystemContext: systemContext})
if err != nil {
return err