diff --git a/pkg/cmd/compose/compose.go b/pkg/cmd/compose/compose.go index 6517412088..8d4991e32e 100644 --- a/pkg/cmd/compose/compose.go +++ b/pkg/cmd/compose/compose.go @@ -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 @@ -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 } @@ -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 } diff --git a/pkg/cmd/image/pull.go b/pkg/cmd/image/pull.go index 0a87df16d5..ff0078f625 100644 --- a/pkg/cmd/image/pull.go +++ b/pkg/cmd/image/pull.go @@ -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") @@ -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 } @@ -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 } diff --git a/pkg/imgutil/imgutil.go b/pkg/imgutil/imgutil.go index 1608d64203..3c8b4ec229 100644 --- a/pkg/imgutil/imgutil.go +++ b/pkg/imgutil/imgutil.go @@ -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 @@ -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) { @@ -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 @@ -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 @@ -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 : connection refused". if !errutil.IsErrHTTPResponseToHTTPSClient(err) && !errutil.IsErrConnectionRefused(err) { @@ -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)") @@ -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 @@ -205,24 +213,24 @@ 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, @@ -230,9 +238,9 @@ func PullImage(ctx context.Context, client *containerd.Client, stdout, stderr io 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) @@ -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 diff --git a/pkg/ipfs/image.go b/pkg/ipfs/image.go index ffe2db4eb3..2130ad397c 100644 --- a/pkg/ipfs/image.go +++ b/pkg/ipfs/image.go @@ -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 @@ -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 @@ -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.