func (mf *v2ManifestFetcher) Fetch(ctx context.Context, ref reference.Named) (*types.ImageInspect, error) { var ( imgInspect *types.ImageInspect err error ) //mf.repo, mf.confirmedV2, err = distribution.NewV2Repository(ctx, mf.repoInfo, mf.endpoint, mf.config.MetaHeaders, mf.config.AuthConfig, "pull") mf.repo, mf.confirmedV2, err = dockerdistribution.NewV2Repository(ctx, mf.repoInfo, mf.endpoint, nil, &mf.authConfig, "pull") if err != nil { logrus.Debugf("Error getting v2 registry: %v", err) return nil, err } imgInspect, err = mf.fetchWithRepository(ctx, ref) if err != nil { if _, ok := err.(fallbackError); ok { return nil, err } if continueOnError(err) { logrus.Errorf("Error trying v2 registry: %v", err) return nil, fallbackError{err: err, confirmedV2: mf.confirmedV2, transportOK: true} } } return imgInspect, err }
func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.NamedTagged, authConfig *types.AuthConfig) (dist.Repository, bool, error) { // get repository info repoInfo, err := daemon.RegistryService.ResolveRepository(ref) if err != nil { return nil, false, err } // makes sure name is not empty or `scratch` if err := distribution.ValidateRepoName(repoInfo.Name()); err != nil { return nil, false, err } // get endpoints endpoints, err := daemon.RegistryService.LookupPullEndpoints(repoInfo.Hostname()) if err != nil { return nil, false, err } // retrieve repository var ( confirmedV2 bool repository dist.Repository lastError error ) for _, endpoint := range endpoints { if endpoint.Version == registry.APIVersion1 { continue } repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull") if lastError == nil && confirmedV2 { break } } return repository, confirmedV2, lastError }
// Push pushes a plugin to a registry. func Push(name string, rs registry.Service, metaHeader http.Header, authConfig *types.AuthConfig, config io.ReadCloser, layers io.ReadCloser) (digest.Digest, error) { ref, err := reference.ParseNamed(name) if err != nil { return "", err } repoInfo, err := rs.ResolveRepository(ref) if err != nil { return "", err } if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil { return "", err } endpoints, err := rs.LookupPushEndpoints(repoInfo.Hostname()) if err != nil { return "", err } var confirmedV2 bool var repository distribution.Repository for _, endpoint := range endpoints { if confirmedV2 && endpoint.Version == registry.APIVersion1 { logrus.Debugf("Skipping v1 endpoint %s because v2 registry was detected", endpoint.URL) continue } repository, confirmedV2, err = dockerdist.NewV2Repository(context.Background(), repoInfo, endpoint, metaHeader, authConfig, "push", "pull") if err != nil { return "", err } if !confirmedV2 { return "", ErrUnSupportedRegistry } logrus.Debugf("Trying to push %s to %s %s", repoInfo.Name(), endpoint.URL, endpoint.Version) // This means that we found an endpoint. and we are ready to push break } // Returns a reference to the repository's blob service. blobs := repository.Blobs(context.Background()) // Descriptor = {mediaType, size, digest} var descs []distribution.Descriptor for i, f := range []io.ReadCloser{config, layers} { bw, err := blobs.Create(context.Background()) if err != nil { logrus.Debugf("Error in blobs.Create: %v", err) return "", err } h := sha256.New() r := io.TeeReader(f, h) _, err = io.Copy(bw, r) if err != nil { logrus.Debugf("Error in io.Copy: %v", err) return "", err } f.Close() mt := MediaTypeLayer if i == 0 { mt = MediaTypeConfig } // Commit completes the write process to the BlobService. // The descriptor arg to Commit is called the "provisional" descriptor and // used for validation. // The returned descriptor should be the one used. Its called the "Canonical" // descriptor. desc, err := bw.Commit(context.Background(), distribution.Descriptor{ MediaType: mt, // XXX: What about the Size? Digest: digest.NewDigest("sha256", h), }) if err != nil { logrus.Debugf("Error in bw.Commit: %v", err) return "", err } // The canonical descriptor is set the mediatype again, just in case. // Dont touch the digest or the size here. desc.MediaType = mt logrus.Debugf("pushed blob: %s %s", desc.MediaType, desc.Digest) descs = append(descs, desc) } // XXX: schema2.Versioned needs a MediaType as well. // "application/vnd.docker.distribution.manifest.v2+json" m, err := schema2.FromStruct(schema2.Manifest{Versioned: schema2.SchemaVersion, Config: descs[0], Layers: descs[1:]}) if err != nil { logrus.Debugf("error in schema2.FromStruct: %v", err) return "", err } msv, err := repository.Manifests(context.Background()) if err != nil { logrus.Debugf("error in repository.Manifests: %v", err) return "", err } _, pl, err := m.Payload() if err != nil { logrus.Debugf("error in m.Payload: %v", err) return "", err } logrus.Debugf("Pushed manifest: %s", pl) tag := DefaultTag if tagged, ok := ref.(reference.NamedTagged); ok { tag = tagged.Tag() } return msv.Put(context.Background(), m, distribution.WithTag(tag)) }
// Pull downloads the plugin from Store func Pull(name string, rs registry.Service, metaheader http.Header, authConfig *types.AuthConfig) (PullData, error) { ref, err := reference.ParseNamed(name) if err != nil { logrus.Debugf("pull.go: error in ParseNamed: %v", err) return nil, err } repoInfo, err := rs.ResolveRepository(ref) if err != nil { logrus.Debugf("pull.go: error in ResolveRepository: %v", err) return nil, err } if err := dockerdist.ValidateRepoName(repoInfo.Name()); err != nil { logrus.Debugf("pull.go: error in ValidateRepoName: %v", err) return nil, err } endpoints, err := rs.LookupPullEndpoints(repoInfo.Hostname()) if err != nil { logrus.Debugf("pull.go: error in LookupPullEndpoints: %v", err) return nil, err } var confirmedV2 bool var repository distribution.Repository for _, endpoint := range endpoints { if confirmedV2 && endpoint.Version == registry.APIVersion1 { logrus.Debugf("Skipping v1 endpoint %s because v2 registry was detected", endpoint.URL) continue } // TODO: reuse contexts repository, confirmedV2, err = dockerdist.NewV2Repository(context.Background(), repoInfo, endpoint, metaheader, authConfig, "pull") if err != nil { logrus.Debugf("pull.go: error in NewV2Repository: %v", err) return nil, err } if !confirmedV2 { logrus.Debugf("pull.go: !confirmedV2") return nil, ErrUnSupportedRegistry } logrus.Debugf("Trying to pull %s from %s %s", repoInfo.Name(), endpoint.URL, endpoint.Version) break } tag := DefaultTag if ref, ok := ref.(reference.NamedTagged); ok { tag = ref.Tag() } // tags := repository.Tags(context.Background()) // desc, err := tags.Get(context.Background(), tag) // if err != nil { // return nil, err // } // msv, err := repository.Manifests(context.Background()) if err != nil { logrus.Debugf("pull.go: error in repository.Manifests: %v", err) return nil, err } manifest, err := msv.Get(context.Background(), "", distribution.WithTag(tag)) if err != nil { // TODO: change 401 to 404 logrus.Debugf("pull.go: error in msv.Get(): %v", err) return nil, err } _, pl, err := manifest.Payload() if err != nil { logrus.Debugf("pull.go: error in manifest.Payload(): %v", err) return nil, err } var m schema2.Manifest if err := json.Unmarshal(pl, &m); err != nil { logrus.Debugf("pull.go: error in json.Unmarshal(): %v", err) return nil, err } pd := &pullData{ repository: repository, manifest: m, } logrus.Debugf("manifest: %s", pl) return pd, nil }