// CmdPull pulls an image or a repository from the registry. // // Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST] func (cli *DockerCli) CmdPull(args ...string) error { cmd := Cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, Cli.DockerCommands["pull"].Description, true) allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository") cmd.Require(flag.Exact, 1) cmd.ParseFlags(args, true) remote := cmd.Arg(0) distributionRef, err := reference.ParseNamed(remote) if err != nil { return err } if *allTags && !reference.IsNameOnly(distributionRef) { return errors.New("tag can't be used with --all-tags/-a") } if !*allTags && reference.IsNameOnly(distributionRef) { distributionRef = reference.WithDefaultTag(distributionRef) fmt.Fprintf(cli.out, "Using default tag: %s\n", reference.DefaultTag) } // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(distributionRef) if err != nil { return err } authConfig := cli.resolveAuthConfig(repoInfo.Index) requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "pull") return cli.imagePullPrivileged(authConfig, distributionRef.String(), "", requestPrivilege) }
// Pull tells Docker to pull image referenced by `name`. func (d Docker) Pull(name string) (builder.Image, error) { ref, err := reference.ParseNamed(name) if err != nil { return nil, err } ref = reference.WithDefaultTag(ref) pullRegistryAuth := &types.AuthConfig{} if len(d.AuthConfigs) > 0 { // The request came with a full auth config file, we prefer to use that repoInfo, err := d.Daemon.RegistryService.ResolveRepository(ref) if err != nil { return nil, err } resolvedConfig := registry.ResolveAuthConfig( d.AuthConfigs, repoInfo.Index, ) pullRegistryAuth = &resolvedConfig } if err := d.Daemon.PullImage(ref, nil, pullRegistryAuth, ioutils.NopWriteCloser(d.OutOld)); err != nil { return nil, err } return d.GetImage(name) }
func runInstall(dockerCli *client.DockerCli, opts pluginOptions) error { named, err := reference.ParseNamed(opts.name) // FIXME: validate if err != nil { return err } named = reference.WithDefaultTag(named) ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } ctx := context.Background() repoInfo, err := registry.ParseRepositoryInfo(named) authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) encodedAuth, err := client.EncodeAuthToBase64(authConfig) if err != nil { return err } requestPrivilege := dockerCli.RegistryAuthenticationPrivilegedFunc(repoInfo.Index, "plugin install") // TODO: pass acceptAllPermissions and noEnable flag options := types.PluginInstallOptions{ RegistryAuth: encodedAuth, Disabled: false, AcceptAllPermissions: opts.grantPerms, AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.name), PrivilegeFunc: requestPrivilege, } return dockerCli.Client().PluginInstall(ctx, ref.String(), options) }
// PullOnBuild tells Docker to pull image referenced by `name`. func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) { ref, err := reference.ParseNamed(name) if err != nil { return nil, err } ref = reference.WithDefaultTag(ref) pullRegistryAuth := &types.AuthConfig{} if len(authConfigs) > 0 { // The request came with a full auth config file, we prefer to use that repoInfo, err := daemon.RegistryService.ResolveRepository(ref) if err != nil { return nil, err } resolvedConfig := registry.ResolveAuthConfig( authConfigs, repoInfo.Index, ) pullRegistryAuth = &resolvedConfig } if err := daemon.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil { return nil, err } return daemon.GetImage(name) }
// sanitizeRepoAndTags parses the raw "t" parameter received from the client // to a slice of repoAndTag. // It also validates each repoName and tag. func sanitizeRepoAndTags(names []string) ([]reference.Named, error) { var ( repoAndTags []reference.Named // This map is used for deduplicating the "-t" parameter. uniqNames = make(map[string]struct{}) ) for _, repo := range names { if repo == "" { continue } ref, err := reference.ParseNamed(repo) if err != nil { return nil, err } ref = reference.WithDefaultTag(ref) if _, isCanonical := ref.(reference.Canonical); isCanonical { return nil, errors.New("build tag cannot contain a digest") } if _, isTagged := ref.(reference.NamedTagged); !isTagged { ref, err = reference.WithTag(ref, reference.DefaultTag) } nameWithTag := ref.String() if _, exists := uniqNames[nameWithTag]; !exists { uniqNames[nameWithTag] = struct{}{} repoAndTags = append(repoAndTags, ref) } } return repoAndTags, nil }
func (cli *HyperClient) PullImage(imageName string) error { distributionRef, err := reference.ParseNamed(imageName) if err != nil { return err } if reference.IsNameOnly(distributionRef) { distributionRef = reference.WithDefaultTag(distributionRef) fmt.Fprintf(cli.out, "Using default tag: %s\n", reference.DefaultTag) } // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(distributionRef) if err != nil { return err } pull := func(auth types.AuthConfig) (io.ReadCloser, string, int, error) { return cli.client.Pull(distributionRef.String(), auth) } body, ctype, _, err := cli.requestWithLogin(repoInfo.Index, pull, "pull") if err != nil { return err } return cli.readStreamOutput(body, ctype, cli.isTerminalOut, cli.out, cli.err) }
func runRemove(dockerCli *command.DockerCli, opts *rmOptions) error { ctx := context.Background() var errs cli.Errors for _, name := range opts.plugins { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } // TODO: pass names to api instead of making multiple api calls if err := dockerCli.Client().PluginRemove(ctx, ref.String(), types.PluginRemoveOptions{Force: opts.force}); err != nil { errs = append(errs, err) continue } fmt.Fprintln(dockerCli.Out(), name) } // Do not simplify to `return errs` because even if errs == nil, it is not a nil-error interface value. if errs != nil { return errs } return nil }
func runPush(dockerCli *command.DockerCli, name string) error { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } ctx := context.Background() repoInfo, err := registry.ParseRepositoryInfo(named) if err != nil { return err } authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) encodedAuth, err := command.EncodeAuthToBase64(authConfig) if err != nil { return err } return dockerCli.Client().PluginPush(ctx, ref.String(), encodedAuth) }
func (c *containerConfig) image() string { raw := c.spec().Image ref, err := reference.ParseNamed(raw) if err != nil { return raw } return reference.WithDefaultTag(ref).String() }
// removeImageRef attempts to parse and remove the given image reference from // this daemon's store of repository tag/digest references. The given // repositoryRef must not be an image ID but a repository name followed by an // optional tag or digest reference. If tag or digest is omitted, the default // tag is used. Returns the resolved image reference and an error. func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, error) { ref = reference.WithDefaultTag(ref) // Ignore the boolean value returned, as far as we're concerned, this // is an idempotent operation and it's okay if the reference didn't // exist in the first place. _, err := daemon.referenceStore.Delete(ref) return ref, err }
func (cli *DockerCli) createContainer(config *container.Config, hostConfig *container.HostConfig, networkingConfig *networktypes.NetworkingConfig, cidfile, name string) (*types.ContainerCreateResponse, error) { var containerIDFile *cidFile if cidfile != "" { var err error if containerIDFile, err = newCIDFile(cidfile); err != nil { return nil, err } defer containerIDFile.Close() } _, ref, err := reference.ParseIDOrReference(config.Image) if err != nil { return nil, err } if ref != nil { ref = reference.WithDefaultTag(ref) } //create the container response, err := cli.client.ContainerCreate(context.Background(), config, hostConfig, networkingConfig, name) //if image not found try to pull it if err != nil { if client.IsErrImageNotFound(err) && ref != nil { fmt.Fprintf(cli.err, "Unable to find image '%s' locally\n", ref.String()) // we don't want to write to stdout anything apart from container.ID if err = cli.pullImageCustomOut(config.Image, cli.err); err != nil { return nil, err } // Retry var retryErr error response, retryErr = cli.client.ContainerCreate(context.Background(), config, hostConfig, networkingConfig, name) if retryErr != nil { return nil, retryErr } } else { return nil, err } } for _, warning := range response.Warnings { fmt.Fprintf(cli.err, "WARNING: %s\n", warning) } if containerIDFile != nil { if err = containerIDFile.Write(response.ID); err != nil { return nil, err } } return &response, nil }
// CmdPull pulls an image or a repository from the registry. // // Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST] func (cli *DockerCli) CmdPull(args ...string) error { cmd := Cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, Cli.DockerCommands["pull"].Description, true) allTags := cmd.Bool([]string{"a", "-all-tags"}, false, "Download all tagged images in the repository") addTrustedFlags(cmd, true) cmd.Require(flag.Exact, 1) cmd.ParseFlags(args, true) remote := cmd.Arg(0) distributionRef, err := reference.ParseNamed(remote) if err != nil { return err } if *allTags && !reference.IsNameOnly(distributionRef) { return errors.New("tag can't be used with --all-tags/-a") } if !*allTags && reference.IsNameOnly(distributionRef) { distributionRef = reference.WithDefaultTag(distributionRef) fmt.Fprintf(cli.out, "Using default tag: %s\n", reference.DefaultTag) } var tag string switch x := distributionRef.(type) { case reference.Canonical: tag = x.Digest().String() case reference.NamedTagged: tag = x.Tag() } registryRef := registry.ParseReference(tag) // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(distributionRef) if err != nil { return err } ctx := context.Background() authConfig := cli.ResolveAuthConfig(ctx, repoInfo.Index) requestPrivilege := cli.RegistryAuthenticationPrivilegedFunc(repoInfo.Index, "pull") if IsTrusted() && !registryRef.HasDigest() { // Check if tag is digest return cli.trustedPull(ctx, repoInfo, registryRef, authConfig, requestPrivilege) } <<<<<<< HEAD return cli.imagePullPrivileged(ctx, authConfig, distributionRef.String(), requestPrivilege, *allTags) }
func runPull(dockerCli *command.DockerCli, opts pullOptions) error { distributionRef, err := reference.ParseNamed(opts.remote) if err != nil { return err } if opts.all && !reference.IsNameOnly(distributionRef) { return errors.New("tag can't be used with --all-tags/-a") } if !opts.all && reference.IsNameOnly(distributionRef) { distributionRef = reference.WithDefaultTag(distributionRef) fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", reference.DefaultTag) } var tag string switch x := distributionRef.(type) { case reference.Canonical: tag = x.Digest().String() case reference.NamedTagged: tag = x.Tag() } registryRef := registry.ParseReference(tag) // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(distributionRef) if err != nil { return err } ctx := context.Background() authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) requestPrivilege := dockerCli.RegistryAuthenticationPrivilegedFunc(repoInfo.Index, "pull") if command.IsTrusted() && !registryRef.HasDigest() { // Check if tag is digest err = trustedPull(ctx, dockerCli, repoInfo, registryRef, authConfig, requestPrivilege) } else { err = imagePullPrivileged(ctx, dockerCli, authConfig, distributionRef.String(), requestPrivilege, opts.all) } if err != nil { if strings.Contains(err.Error(), "target is a plugin") { return errors.New(err.Error() + " - Use `docker plugin install`") } return err } return nil }
func getPluginName(name string) (string, error) { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return "", err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return "", fmt.Errorf("invalid name: %s", named.String()) } return ref.String(), nil }
func runSet(dockerCli *client.DockerCli, name string, args []string) error { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } return dockerCli.Client().PluginSet(context.Background(), ref.String(), args) }
// parseImageName converts a string into a reference and tag value. func parseImageName(img string) (reference.Named, string, error) { ref, err := reference.ParseNamed(img) if err != nil { return nil, "", err } ref = reference.WithDefaultTag(ref) var tag string switch x := ref.(type) { case reference.Canonical: tag = x.Digest().String() case reference.NamedTagged: tag = x.Tag() } return ref, tag, nil }
// Get returns an enabled plugin matching the given name and capability. func (ps *Store) Get(name, capability string, mode int) (plugingetter.CompatPlugin, error) { var ( p *v2.Plugin err error ) // Lookup using new model. if ps != nil { fullName := name if named, err := reference.ParseNamed(fullName); err == nil { // FIXME: validate if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return nil, fmt.Errorf("invalid name: %s", named.String()) } fullName = ref.String() } p, err = ps.GetByName(fullName) if err == nil { p.Lock() p.RefCount += mode p.Unlock() if p.IsEnabled() { return p.FilterByCap(capability) } // Plugin was found but it is disabled, so we should not fall back to legacy plugins // but we should error out right away return nil, ErrNotFound(fullName) } if _, ok := err.(ErrNotFound); !ok { return nil, err } } // Lookup using legacy model. if allowV1PluginsFallback { p, err := plugins.Get(name, capability) if err != nil { return nil, fmt.Errorf("legacy plugin: %v", err) } return p, nil } return nil, err }
// Pull pulls a plugin, check if the correct privileges are provided and install the plugin. func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, metaHeader http.Header, authConfig *types.AuthConfig, privileges types.PluginPrivileges, outStream io.Writer) (err error) { pm.muGC.RLock() defer pm.muGC.RUnlock() // revalidate because Pull is public nameref, err := reference.ParseNamed(name) if err != nil { return errors.Wrapf(err, "failed to parse %q", name) } name = reference.WithDefaultTag(nameref).String() if err := pm.config.Store.validateName(name); err != nil { return err } tmpRootFSDir, err := ioutil.TempDir(pm.tmpDir(), ".rootfs") defer os.RemoveAll(tmpRootFSDir) dm := &downloadManager{ tmpDir: tmpRootFSDir, blobStore: pm.blobStore, } pluginPullConfig := &distribution.ImagePullConfig{ Config: distribution.Config{ MetaHeaders: metaHeader, AuthConfig: authConfig, RegistryService: pm.config.RegistryService, ImageEventLogger: pm.config.LogPluginEvent, ImageStore: dm, }, DownloadManager: dm, // todo: reevaluate if possible to substitute distribution/xfer dependencies instead Schema2Types: distribution.PluginTypes, } err = pm.pull(ctx, ref, pluginPullConfig, outStream) if err != nil { go pm.GC() return err } if _, err := pm.createPlugin(name, dm.configDigest, dm.blobs, tmpRootFSDir, &privileges); err != nil { return err } return nil }
// requirementsForImage selects the appropriate requirements for image. func (pc *PolicyContext) requirementsForImage(image types.Image) (PolicyRequirements, error) { imageIdentity := image.IntendedDockerReference() // We don't technically need to parse it first in order to match the full name:tag, // but do so anyway to ensure that the intended identity really does follow that // format, or at least that it is not demonstrably wrong. ref, err := reference.ParseNamed(imageIdentity) if err != nil { return nil, err } ref = reference.WithDefaultTag(ref) // Look for a full match. fullyExpanded, err := fullyExpandedDockerReference(ref) if err != nil { // Coverage: This cannot currently happen. return nil, err } if req, ok := pc.Policy.Specific[fullyExpanded]; ok { logrus.Debugf(" Using specific policy section %s", fullyExpanded) return req, nil } // Look for a match of the repository, and then of the possible parent // namespaces. Note that this only happens on the expanded host names // and repository names, i.e. "busybox" is looked up as "docker.io/library/busybox", // then in its parent "docker.io/library"; in none of "busybox", // un-namespaced "library" nor in "" implicitly representing "library/". // // ref.FullName() == ref.Hostname() + "/" + ref.RemoteName(), so the last // iteration matches the host name (for any namespace). name := ref.FullName() for { if req, ok := pc.Policy.Specific[name]; ok { logrus.Debugf(" Using specific policy section %s", name) return req, nil } lastSlash := strings.LastIndex(name, "/") if lastSlash == -1 { break } name = name[:lastSlash] } logrus.Debugf(" Using default policy section") return pc.Policy.Default, nil }
// LookupWithCapability returns a plugin matching the given name and capability. func LookupWithCapability(name, capability string) (Plugin, error) { var ( p *plugin err error ) handleLegacy := true if manager != nil { fullName := name if named, err := reference.ParseNamed(fullName); err == nil { // FIXME: validate if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return nil, fmt.Errorf("invalid name: %s", named.String()) } fullName = ref.String() } p, err = manager.get(fullName) if err != nil { if _, ok := err.(ErrNotFound); !ok { return nil, err } handleLegacy = manager.handleLegacy } else { handleLegacy = false } } if handleLegacy { p, err := plugins.Get(name, capability) if err != nil { return nil, fmt.Errorf("legacy plugin: %v", err) } return p, nil } else if err != nil { return nil, err } capability = strings.ToLower(capability) for _, typ := range p.PluginObj.Manifest.Interface.Types { if typ.Capability == capability && typ.Prefix == "docker" { return p, nil } } return nil, ErrInadequateCapability{name, capability} }
func runDisable(dockerCli *command.DockerCli, name string) error { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } if err := dockerCli.Client().PluginDisable(context.Background(), ref.String()); err != nil { return err } fmt.Fprintln(dockerCli.Out(), name) return nil }
// Get returns the imageID for a parsed reference func (store *repoCache) Get(ref reference.Named) (string, error) { defer trace.End(trace.Begin("")) ref = reference.WithDefaultTag(ref) store.mu.RLock() defer store.mu.RUnlock() repository, exists := store.Repositories[ref.Name()] if !exists || repository == nil { return "", ErrDoesNotExist } imageID, exists := repository[ref.String()] if !exists { return "", ErrDoesNotExist } return imageID, nil }
func runInstall(dockerCli *command.DockerCli, opts pluginOptions) error { named, err := reference.ParseNamed(opts.name) // FIXME: validate if err != nil { return err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } ctx := context.Background() repoInfo, err := registry.ParseRepositoryInfo(named) if err != nil { return err } authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) encodedAuth, err := command.EncodeAuthToBase64(authConfig) if err != nil { return err } registryAuthFunc := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "plugin install") options := types.PluginInstallOptions{ RegistryAuth: encodedAuth, Disabled: opts.disable, AcceptAllPermissions: opts.grantPerms, AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.name), // TODO: Rename PrivilegeFunc, it has nothing to do with privileges PrivilegeFunc: registryAuthFunc, Args: opts.args, } if err := dockerCli.Client().PluginInstall(ctx, ref.String(), options); err != nil { return err } fmt.Fprintln(dockerCli.Out(), opts.name) return nil }
// Delete deletes a reference from the store. It returns true if a deletion // happened, or false otherwise. func (store *repoCache) Delete(ref reference.Named, save bool) (bool, error) { defer trace.End(trace.Begin("")) ref = reference.WithDefaultTag(ref) store.mu.Lock() defer store.mu.Unlock() var err error // return code -- assume success rtc := true repoName := ref.Name() repository, exists := store.Repositories[repoName] if !exists { return false, ErrDoesNotExist } refStr := ref.String() if imageID, exists := repository[refStr]; exists { delete(repository, refStr) if len(repository) == 0 { delete(store.Repositories, repoName) } if store.referencesByIDCache[imageID] != nil { delete(store.referencesByIDCache[imageID], refStr) if len(store.referencesByIDCache[imageID]) == 0 { delete(store.referencesByIDCache, imageID) } } if layer, exists := store.images[imageID]; exists { delete(store.Layers, imageID) delete(store.images, layer) } if save { err = store.Save() if err != nil { rtc = false } } return rtc, err } return false, ErrDoesNotExist }
func (cli *HyperClient) PullImage(imageName string) error { distributionRef, err := reference.ParseNamed(imageName) if err != nil { return err } if reference.IsNameOnly(distributionRef) { distributionRef = reference.WithDefaultTag(distributionRef) fmt.Fprintf(cli.out, "Using default tag: %s\n", reference.DefaultTag) } // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(distributionRef) if err != nil { return err } v := url.Values{} v.Set("imageName", distributionRef.String()) _, _, err = cli.clientRequestAttemptLogin("POST", "/image/create?"+v.Encode(), nil, cli.out, repoInfo.Index, "pull") return err }
func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error { client := dockerCli.Client() ctx := context.Background() getRef := func(name string) (interface{}, []byte, error) { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return nil, nil, err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return nil, nil, fmt.Errorf("invalid name: %s", named.String()) } return client.PluginInspectWithRaw(ctx, ref.String()) } return inspect.Inspect(dockerCli.Out(), opts.pluginNames, opts.format, getRef) }
func resolveServiceImageDigest(dockerCli *command.DockerCli, service *swarm.ServiceSpec) error { if !command.IsTrusted() { // Digests are resolved by the daemon when not using content // trust. return nil } image := service.TaskTemplate.ContainerSpec.Image // We only attempt to resolve the digest if the reference // could be parsed as a digest reference. Specifying an image ID // is valid but not resolvable. There is no warning message for // an image ID because it's valid to use one. if _, err := digest.ParseDigest(image); err == nil { return nil } ref, err := reference.ParseNamed(image) if err != nil { return fmt.Errorf("Could not parse image reference %s", service.TaskTemplate.ContainerSpec.Image) } if _, ok := ref.(reference.Canonical); !ok { ref = reference.WithDefaultTag(ref) taggedRef, ok := ref.(reference.NamedTagged) if !ok { // This should never happen because a reference either // has a digest, or WithDefaultTag would give it a tag. return errors.New("Failed to resolve image digest using content trust: reference is missing a tag") } resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef) if err != nil { return fmt.Errorf("Failed to resolve image digest using content trust: %v", err) } logrus.Debugf("resolved image tag to %s using content trust", resolvedImage.String()) service.TaskTemplate.ContainerSpec.Image = resolvedImage.String() } return nil }
func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error { ref, err := reference.ParseNamed(image) if err != nil { return err } var tag string switch x := reference.WithDefaultTag(ref).(type) { case reference.Canonical: tag = x.Digest().String() case reference.NamedTagged: tag = x.Tag() } // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(ref) if err != nil { return err } authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index) encodedAuth, err := encodeAuthToBase64(authConfig) if err != nil { return err } options := types.ImageCreateOptions{ Parent: ref.Name(), Tag: tag, RegistryAuth: encodedAuth, } responseBody, err := cli.client.ImageCreate(options) if err != nil { return err } defer responseBody.Close() return jsonmessage.DisplayJSONMessagesStream(responseBody, out, cli.outFd, cli.isTerminalOut, nil) }
// imageWithDigestString takes an image such as name or name:tag // and returns the image pinned to a digest, such as name@sha256:34234... // Due to the difference between the docker/docker/reference, and the // docker/distribution/reference packages, we're parsing the image twice. // As the two packages converge, this function should be simplified. // TODO(nishanttotla): After the packages converge, the function must // convert distreference.Named -> distreference.Canonical, and the logic simplified. func (c *Cluster) imageWithDigestString(ctx context.Context, image string, authConfig *apitypes.AuthConfig) (string, error) { if _, err := digest.ParseDigest(image); err == nil { return "", errors.New("image reference is an image ID") } ref, err := distreference.ParseNamed(image) if err != nil { return "", err } // only query registry if not a canonical reference (i.e. with digest) if _, ok := ref.(distreference.Canonical); !ok { // create a docker/docker/reference Named object because GetRepository needs it dockerRef, err := reference.ParseNamed(image) if err != nil { return "", err } dockerRef = reference.WithDefaultTag(dockerRef) namedTaggedRef, ok := dockerRef.(reference.NamedTagged) if !ok { return "", errors.New("unable to cast image to NamedTagged reference object") } repo, _, err := c.config.Backend.GetRepository(ctx, namedTaggedRef, authConfig) if err != nil { return "", err } dscrptr, err := repo.Tags(ctx).Get(ctx, namedTaggedRef.Tag()) if err != nil { return "", err } namedDigestedRef, err := distreference.WithDigest(distreference.EnsureTagged(ref), dscrptr.Digest) if err != nil { return "", err } return namedDigestedRef.String(), nil } // reference already contains a digest, so just return it return ref.String(), nil }
func (ps *Store) resolvePluginID(idOrName string) (string, error) { ps.RLock() // todo: fix defer ps.RUnlock() if validFullID.MatchString(idOrName) { return idOrName, nil } ref, err := reference.ParseNamed(idOrName) if err != nil { return "", errors.WithStack(ErrNotFound(idOrName)) } if _, ok := ref.(reference.Canonical); ok { logrus.Warnf("canonical references cannot be resolved: %v", ref.String()) return "", errors.WithStack(ErrNotFound(idOrName)) } fullRef := reference.WithDefaultTag(ref) for _, p := range ps.plugins { if p.PluginObj.Name == fullRef.String() { return p.PluginObj.ID, nil } } var found *v2.Plugin for id, p := range ps.plugins { // this can be optimized if strings.HasPrefix(id, idOrName) { if found != nil { return "", errors.WithStack(ErrAmbiguous(idOrName)) } found = p } } if found == nil { return "", errors.WithStack(ErrNotFound(idOrName)) } return found.PluginObj.ID, nil }