Skip to content

Commit

Permalink
Move image pull args into struct
Browse files Browse the repository at this point in the history
Signed-off-by: David Son <davbson@amazon.com>
  • Loading branch information
sondavidb committed Mar 22, 2024
1 parent 78b66fd commit d055293
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 34 deletions.
16 changes: 12 additions & 4 deletions pkg/cmd/compose/compose.go
Expand Up @@ -110,6 +110,16 @@ func New(client *containerd.Client, globalOptions types.GlobalCommandOptions, op
ocispecPlatforms = []ocispec.Platform{parsed} // no append
}

imageConfig := &imgutil.Config{
Stdout: stdout,
Stderr: stderr,
Snapshotter: globalOptions.Snapshotter,
OcispecPlatforms: ocispecPlatforms,
Unpack: nil,
Quiet: quiet,
RFlags: imgutil.RemoteSnapshotterFlags{},
}

// IPFS reference
if scheme, ref, err := referenceutil.ParseIPFSRefWithScheme(imageName); err == nil {
var ipfsPath string
Expand All @@ -124,8 +134,7 @@ func New(client *containerd.Client, globalOptions types.GlobalCommandOptions, op
}
ipfsPath = dir
}
_, err = ipfs.EnsureImage(ctx, client, stdout, stderr, globalOptions.Snapshotter, scheme, ref,
pullMode, ocispecPlatforms, nil, quiet, ipfsPath, imgutil.RemoteSnapshotterFlags{})
_, err = ipfs.EnsureImage(ctx, client, scheme, ref, pullMode, ipfsPath, imageConfig)
return err
}

Expand All @@ -135,8 +144,7 @@ func New(client *containerd.Client, globalOptions types.GlobalCommandOptions, op
return err
}

_, err = imgutil.EnsureImage(ctx, client, stdout, stderr, globalOptions.Snapshotter, ref,
pullMode, globalOptions.InsecureRegistry, globalOptions.HostsDir, ocispecPlatforms, nil, quiet, imgutil.RemoteSnapshotterFlags{})
_, err = imgutil.EnsureImage(ctx, client, ref, pullMode, globalOptions.InsecureRegistry, globalOptions.HostsDir, imageConfig)
return err
}

Expand Down
16 changes: 12 additions & 4 deletions pkg/cmd/image/pull.go
Expand Up @@ -57,6 +57,16 @@ func Pull(ctx context.Context, client *containerd.Client, rawRef string, options
func EnsureImage(ctx context.Context, client *containerd.Client, rawRef string, ocispecPlatforms []v1.Platform, pull string, unpack *bool, quiet bool, options types.ImagePullOptions) (*imgutil.EnsuredImage, error) {
var ensured *imgutil.EnsuredImage

imageConfig := &imgutil.Config{
Stdout: options.Stdout,
Stderr: options.Stdout,
Snapshotter: options.GOptions.Snapshotter,
OcispecPlatforms: ocispecPlatforms,
Unpack: unpack,
Quiet: quiet,
RFlags: options.RFlags,
}

if scheme, ref, err := referenceutil.ParseIPFSRefWithScheme(rawRef); err == nil {
if options.VerifyOptions.Provider != "none" {
return nil, errors.New("--verify flag is not supported on IPFS as of now")
Expand All @@ -75,8 +85,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, rawRef string,
ipfsPath = dir
}

ensured, err = ipfs.EnsureImage(ctx, client, options.Stdout, options.Stderr, options.GOptions.Snapshotter, scheme, ref,
pull, ocispecPlatforms, unpack, quiet, ipfsPath, options.RFlags)
ensured, err = ipfs.EnsureImage(ctx, client, scheme, ref, pull, ipfsPath, imageConfig)
if err != nil {
return nil, err
}
Expand All @@ -88,8 +97,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, rawRef string,
return nil, err
}

ensured, err = imgutil.EnsureImage(ctx, client, options.Stdout, options.Stderr, options.GOptions.Snapshotter, ref,
pull, options.GOptions.InsecureRegistry, options.GOptions.HostsDir, ocispecPlatforms, unpack, quiet, options.RFlags)
ensured, err = imgutil.EnsureImage(ctx, client, ref, pull, options.GOptions.InsecureRegistry, options.GOptions.HostsDir, imageConfig)
if err != nil {
return nil, err
}
Expand Down
52 changes: 30 additions & 22 deletions pkg/imgutil/imgutil.go
Expand Up @@ -42,6 +42,9 @@ import (
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)

// PullMode is either one of "always", "missing", "never"
type PullMode = string

// EnsuredImage contains the image existed in containerd and its metadata.
type EnsuredImage struct {
Ref string
Expand All @@ -51,8 +54,15 @@ type EnsuredImage struct {
Remote bool // true for stargz or overlaybd
}

// PullMode is either one of "always", "missing", "never"
type PullMode = string
type Config struct {
Stdout io.Writer
Stderr io.Writer
Snapshotter string
OcispecPlatforms []ocispec.Platform
Unpack *bool
Quiet bool
RFlags RemoteSnapshotterFlags
}

// GetExistingImage returns the specified image if exists in containerd. Return errdefs.NotFound() if not exists.
func GetExistingImage(ctx context.Context, client *containerd.Client, snapshotter, rawRef string, platform ocispec.Platform) (*EnsuredImage, error) {
Expand Down Expand Up @@ -101,9 +111,7 @@ func GetExistingImage(ctx context.Context, client *containerd.Client, snapshotte
// EnsureImage ensures the image.
//
// # When insecure is set, skips verifying certs, and also falls back to HTTP when the registry does not speak HTTPS
//
// FIXME: this func has too many args
func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr io.Writer, snapshotter, rawRef string, mode PullMode, insecure bool, hostsDirs []string, ocispecPlatforms []ocispec.Platform, unpack *bool, quiet bool, rFlags RemoteSnapshotterFlags) (*EnsuredImage, error) {
func EnsureImage(ctx context.Context, client *containerd.Client, rawRef string, mode PullMode, insecure bool, hostsDirs []string, imageConfig *Config) (*EnsuredImage, error) {
switch mode {
case "always", "missing", "never":
// NOP
Expand All @@ -112,8 +120,8 @@ func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr
}

// if not `always` pull and given one platform and image found locally, return existing image directly.
if mode != "always" && len(ocispecPlatforms) == 1 {
if res, err := GetExistingImage(ctx, client, snapshotter, rawRef, ocispecPlatforms[0]); err == nil {
if mode != "always" && len(imageConfig.OcispecPlatforms) == 1 {
if res, err := GetExistingImage(ctx, client, imageConfig.Snapshotter, rawRef, imageConfig.OcispecPlatforms[0]); err == nil {
return res, nil
} else if !errdefs.IsNotFound(err) {
return nil, err
Expand Down Expand Up @@ -142,7 +150,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr
return nil, err
}

img, err := PullImage(ctx, client, stdout, stderr, snapshotter, resolver, ref, ocispecPlatforms, unpack, quiet, rFlags)
img, err := PullImage(ctx, client, resolver, ref, imageConfig)
if err != nil {
// In some circumstance (e.g. people just use 80 port to support pure http), the error will contain message like "dial tcp <port>: connection refused".
if !errutil.IsErrHTTPResponseToHTTPSClient(err) && !errutil.IsErrConnectionRefused(err) {
Expand All @@ -155,7 +163,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr
if err != nil {
return nil, err
}
return PullImage(ctx, client, stdout, stderr, snapshotter, resolver, ref, ocispecPlatforms, unpack, quiet, rFlags)
return PullImage(ctx, client, resolver, ref, imageConfig)
}
log.G(ctx).WithError(err).Errorf("server %q does not seem to support HTTPS", refDomain)
log.G(ctx).Info("Hint: you may want to try --insecure-registry to allow plain HTTP (if you are in a trusted network)")
Expand Down Expand Up @@ -194,7 +202,7 @@ func ResolveDigest(ctx context.Context, rawRef string, insecure bool, hostsDirs
}

// PullImage pulls an image using the specified resolver.
func PullImage(ctx context.Context, client *containerd.Client, stdout, stderr io.Writer, snapshotter string, resolver remotes.Resolver, ref string, ocispecPlatforms []ocispec.Platform, unpack *bool, quiet bool, rFlags RemoteSnapshotterFlags) (*EnsuredImage, error) {
func PullImage(ctx context.Context, client *containerd.Client, resolver remotes.Resolver, ref string, imageConfig *Config) (*EnsuredImage, error) {
ctx, done, err := client.WithLease(ctx)
if err != nil {
return nil, err
Expand All @@ -205,34 +213,34 @@ func PullImage(ctx context.Context, client *containerd.Client, stdout, stderr io
config := &pull.Config{
Resolver: resolver,
RemoteOpts: []containerd.RemoteOpt{},
Platforms: ocispecPlatforms, // empty for all-platforms
Platforms: imageConfig.OcispecPlatforms, // empty for all-platforms
}
if !quiet {
config.ProgressOutput = stderr
if !imageConfig.Quiet {
config.ProgressOutput = imageConfig.Stderr
}

// unpack(B) if given 1 platform unless specified by `unpack`
unpackB := len(ocispecPlatforms) == 1
if unpack != nil {
unpackB = *unpack
if unpackB && len(ocispecPlatforms) != 1 {
unpackB := len(imageConfig.OcispecPlatforms) == 1
if imageConfig.Unpack != nil {
unpackB = *imageConfig.Unpack
if unpackB && len(imageConfig.OcispecPlatforms) != 1 {
return nil, fmt.Errorf("unpacking requires a single platform to be specified (e.g., --platform=amd64)")
}
}

snOpt := getSnapshotterOpts(snapshotter)
snOpt := getSnapshotterOpts(imageConfig.Snapshotter)
if unpackB {
log.G(ctx).Debugf("The image will be unpacked for platform %q, snapshotter %q.", ocispecPlatforms[0], snapshotter)
log.G(ctx).Debugf("The image will be unpacked for platform %q, snapshotter %q.", imageConfig.OcispecPlatforms[0], imageConfig.Snapshotter)
imgcryptPayload := imgcrypt.Payload{}
imgcryptUnpackOpt := encryption.WithUnpackConfigApplyOpts(encryption.WithDecryptedUnpack(&imgcryptPayload))
config.RemoteOpts = append(config.RemoteOpts,
containerd.WithPullUnpack,
containerd.WithUnpackOpts([]containerd.UnpackOpt{imgcryptUnpackOpt}))

// different remote snapshotters will update pull.Config separately
snOpt.apply(config, ref, rFlags)
snOpt.apply(config, ref, imageConfig.RFlags)
} else {
log.G(ctx).Debugf("The image will not be unpacked. Platforms=%v.", ocispecPlatforms)
log.G(ctx).Debugf("The image will not be unpacked. Platforms=%v.", imageConfig.OcispecPlatforms)
}

containerdImage, err = pull.Pull(ctx, client, ref, config)
Expand All @@ -247,7 +255,7 @@ func PullImage(ctx context.Context, client *containerd.Client, stdout, stderr io
Ref: ref,
Image: containerdImage,
ImageConfig: *imgConfig,
Snapshotter: snapshotter,
Snapshotter: imageConfig.Snapshotter,
Remote: snOpt.isRemote(),
}
return res, nil
Expand Down
8 changes: 4 additions & 4 deletions pkg/ipfs/image.go
Expand Up @@ -40,7 +40,7 @@ import (
const ipfsPathEnv = "IPFS_PATH"

// EnsureImage pull the specified image from IPFS.
func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr io.Writer, snapshotter string, scheme string, ref string, mode imgutil.PullMode, ocispecPlatforms []ocispec.Platform, unpack *bool, quiet bool, ipfsPath string, rFlags imgutil.RemoteSnapshotterFlags) (*imgutil.EnsuredImage, error) {
func EnsureImage(ctx context.Context, client *containerd.Client, scheme string, ref string, mode imgutil.PullMode, ipfsPath string, imageConfig *imgutil.Config) (*imgutil.EnsuredImage, error) {
switch mode {
case "always", "missing", "never":
// NOP
Expand All @@ -55,8 +55,8 @@ func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr
}

// if not `always` pull and given one platform and image found locally, return existing image directly.
if mode != "always" && len(ocispecPlatforms) == 1 {
if res, err := imgutil.GetExistingImage(ctx, client, snapshotter, ref, ocispecPlatforms[0]); err == nil {
if mode != "always" && len(imageConfig.OcispecPlatforms) == 1 {
if res, err := imgutil.GetExistingImage(ctx, client, imageConfig.Snapshotter, ref, imageConfig.OcispecPlatforms[0]); err == nil {
return res, nil
} else if !errdefs.IsNotFound(err) {
return nil, err
Expand All @@ -73,7 +73,7 @@ func EnsureImage(ctx context.Context, client *containerd.Client, stdout, stderr
if err != nil {
return nil, err
}
return imgutil.PullImage(ctx, client, stdout, stderr, snapshotter, r, ref, ocispecPlatforms, unpack, quiet, rFlags)
return imgutil.PullImage(ctx, client, r, ref, imageConfig)
}

// Push pushes the specified image to IPFS.
Expand Down

0 comments on commit d055293

Please sign in to comment.