// 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) }
func (prm *prmExactReference) matchesDockerReference(image types.Image, signatureDockerReference string) bool { intended, signature, err := parseDockerReferences(prm.DockerReference, signatureDockerReference) if err != nil { return false } // prm.DockerReference and signatureDockerReference should be exact; so, verify that now. if reference.IsNameOnly(intended) || reference.IsNameOnly(signature) { return false } return signature.String() == intended.String() }
func (prm *prmMatchExact) matchesDockerReference(image types.Image, signatureDockerReference string) bool { intended, signature, err := parseDockerReferences(image.IntendedDockerReference(), signatureDockerReference) if err != nil { return false } // Do not add default tags: image.IntendedDockerReference() has it added already per its construction, and signatureDockerReference should be exact; so, verify that now. if reference.IsNameOnly(intended) || reference.IsNameOnly(signature) { return false } return signature.String() == intended.String() }
// 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 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 (p *v2Pusher) pushV2Repository(ctx context.Context) (err error) { if namedTagged, isNamedTagged := p.ref.(reference.NamedTagged); isNamedTagged { imageID, err := p.config.ReferenceStore.Get(p.ref) if err != nil { return fmt.Errorf("tag does not exist: %s", p.ref.String()) } return p.pushV2Tag(ctx, namedTagged, imageID) } if !reference.IsNameOnly(p.ref) { return errors.New("cannot push a digest reference") } // Pull all tags pushed := 0 for _, association := range p.config.ReferenceStore.ReferencesByName(p.ref) { if namedTagged, isNamedTagged := association.Ref.(reference.NamedTagged); isNamedTagged { pushed++ if err := p.pushV2Tag(ctx, namedTagged, association.ImageID); err != nil { return err } } } if pushed == 0 { return fmt.Errorf("no tags to push for %s", p.repoInfo.Name()) } return 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 (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) { var layersDownloaded bool if !reference.IsNameOnly(ref) { var err error layersDownloaded, err = p.pullV2Tag(ctx, ref) if err != nil { return err } } else { manSvc, err := p.repo.Manifests(ctx) if err != nil { return err } tags, err := manSvc.Tags() if err != nil { // If this repository doesn't exist on V2, we should // permit a fallback to V1. return allowV1Fallback(err) } // The v2 registry knows about this repository, so we will not // allow fallback to the v1 protocol even if we encounter an // error later on. p.confirmedV2 = true // This probably becomes a lot nicer after the manifest // refactor... for _, tag := range tags { tagRef, err := reference.WithTag(ref, tag) if err != nil { return err } pulledNew, err := p.pullV2Tag(ctx, tagRef) if err != nil { // Since this is the pull-all-tags case, don't // allow an error pulling a particular tag to // make the whole pull fall back to v1. if fallbackErr, ok := err.(fallbackError); ok { return fallbackErr.err } return err } // pulledNew is true if either new layers were downloaded OR if existing images were newly tagged // TODO(tiborvass): should we change the name of `layersDownload`? What about message in WriteStatus? layersDownloaded = layersDownloaded || pulledNew } } writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded) return nil }
// newPRMExactReference is NewPRMExactReference, except it resturns the private type. func newPRMExactReference(dockerReference string) (*prmExactReference, error) { ref, err := reference.ParseNamed(dockerReference) if err != nil { return nil, InvalidPolicyFormatError(fmt.Sprintf("Invalid format of dockerReference %s: %s", dockerReference, err.Error())) } if reference.IsNameOnly(ref) { return nil, InvalidPolicyFormatError(fmt.Sprintf("dockerReference %s contains neither a tag nor digest", dockerReference)) } return &prmExactReference{ prmCommon: prmCommon{Type: prmTypeExactReference}, DockerReference: dockerReference, }, 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) }
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 }
// 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 }
// 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 (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) { var refs []reference.Named if !reference.IsNameOnly(ref) { refs = []reference.Named{ref} } else { manSvc, err := p.repo.Manifests(ctx) if err != nil { return err } tags, err := manSvc.Tags() if err != nil { return err } // If this call succeeded, we can be confident that the // registry on the other side speaks the v2 protocol. p.confirmedV2 = true // This probably becomes a lot nicer after the manifest // refactor... for _, tag := range tags { tagRef, err := reference.WithTag(ref, tag) if err != nil { return err } refs = append(refs, tagRef) } } var layersDownloaded bool for _, pullRef := range refs { // pulledNew is true if either new layers were downloaded OR if existing images were newly tagged // TODO(tiborvass): should we change the name of `layersDownload`? What about message in WriteStatus? pulledNew, err := p.pullV2Tag(ctx, pullRef) if err != nil { return err } layersDownloaded = layersDownloaded || pulledNew } writeStatus(ref.String(), p.config.ProgressOutput, layersDownloaded) return nil }
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 }
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 }
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 (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 }
// LookupWithCapability returns a plugin matching the given name and capability. func LookupWithCapability(name, capability string) (CompatPlugin, error) { var ( p *v2.Plugin err error ) // Lookup using new model. if store != 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 = store.GetByName(fullName) if err == nil { return p.FilterByCap(capability) } 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 }
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 } responseBody, err := dockerCli.Client().PluginPush(ctx, ref.String(), encodedAuth) if err != nil { return err } defer responseBody.Close() if command.IsTrusted() { repoInfo.Class = "plugin" return image.PushTrustedReference(dockerCli, repoInfo, named, authConfig, responseBody) } return jsonmessage.DisplayJSONMessagesToStream(responseBody, dockerCli.Out(), nil) }
// ParseReference parses the -reference parameter and populate options struct func ParseReference() error { // Validate and parse reference name ref, err := reference.ParseNamed(options.reference) if err != nil { return err } options.tag = reference.DefaultTag if !reference.IsNameOnly(ref) { if tagged, ok := ref.(reference.NamedTagged); ok { options.tag = tagged.Tag() } } options.registry = DefaultDockerURL if ref.Hostname() != reference.DefaultHostname { options.registry = ref.Hostname() } options.image = ref.RemoteName() return nil }
func runEnable(dockerCli *command.DockerCli, opts *enableOpts) error { name := opts.name 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 opts.timeout < 0 { return fmt.Errorf("negative timeout %d is invalid", opts.timeout) } if err := dockerCli.Client().PluginEnable(context.Background(), ref.String(), types.PluginEnableOptions{Timeout: opts.timeout}); err != nil { return err } fmt.Fprintln(dockerCli.Out(), name) return nil }
func runInspect(dockerCli *client.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()) } p, err := dockerCli.Client().PluginInspect(context.Background(), ref.String()) if err != nil { return err } b, err := json.MarshalIndent(p, "", "\t") if err != nil { return err } _, err = dockerCli.Out().Write(b) return err }
// ParseReference parses the -reference parameter and populate options struct func (ic *ImageC) ParseReference() error { // Validate and parse reference name ref, err := reference.ParseNamed(ic.Reference) if err != nil { log.Warn("Error while parsing reference %s: %#v", ic.Reference, err) return err } ic.Tag = reference.DefaultTag if !reference.IsNameOnly(ref) { if tagged, ok := ref.(reference.NamedTagged); ok { ic.Tag = tagged.Tag() } } ic.Registry = DefaultDockerURL if ref.Hostname() != reference.DefaultHostname { ic.Registry = ref.Hostname() } ic.Image = ref.RemoteName() return nil }
func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor, error) { imgDescr := make(map[image.ID]*imageDescriptor) addAssoc := func(id image.ID, ref reference.Named) { if _, ok := imgDescr[id]; !ok { imgDescr[id] = &imageDescriptor{} } if ref != nil { var tagged reference.NamedTagged if _, ok := ref.(reference.Canonical); ok { return } var ok bool if tagged, ok = ref.(reference.NamedTagged); !ok { var err error if tagged, err = reference.WithTag(ref, reference.DefaultTag); err != nil { return } } for _, t := range imgDescr[id].refs { if tagged.String() == t.String() { return } } imgDescr[id].refs = append(imgDescr[id].refs, tagged) } } for _, name := range names { id, ref, err := reference.ParseIDOrReference(name) if err != nil { return nil, err } if id != "" { _, err := l.is.Get(image.ID(id)) if err != nil { return nil, err } addAssoc(image.ID(id), nil) continue } if ref.Name() == string(digest.Canonical) { imgID, err := l.is.Search(name) if err != nil { return nil, err } addAssoc(imgID, nil) continue } if reference.IsNameOnly(ref) { assocs := l.rs.ReferencesByName(ref) for _, assoc := range assocs { addAssoc(assoc.ImageID, assoc.Ref) } if len(assocs) == 0 { imgID, err := l.is.Search(name) if err != nil { return nil, err } addAssoc(imgID, nil) } continue } var imgID image.ID if imgID, err = l.rs.Get(ref); err != nil { return nil, err } addAssoc(imgID, ref) } return imgDescr, nil }