func (s *TagStore) pullFromV2Mirror(mirrorEndpoint *registry.Endpoint, repoInfo *registry.RepositoryInfo, imagePullConfig *ImagePullConfig, tag string, sf *streamformatter.StreamFormatter, logName string) error { tr := transport.NewTransport( registry.NewTransport(registry.ReceiveTimeout, mirrorEndpoint.IsSecure), registry.DockerHeaders(imagePullConfig.MetaHeaders)..., ) client := registry.HTTPClient(tr) mirrorSession, err := registry.NewSession(client, &cliconfig.AuthConfig{}, mirrorEndpoint) if err != nil { return err } glog.V(1).Infof("Pulling v2 repository with local name %q from %s", repoInfo.LocalName, mirrorEndpoint.URL) if err := s.pullV2Repository(mirrorSession, imagePullConfig.OutStream, repoInfo, tag, sf); err != nil { return err } s.eventsService.Log("pull", logName, "") return nil }
// FIXME: Allow to interrupt current push when new push of same image is done. func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) error { var ( sf = streamformatter.NewJSONStreamFormatter() ) // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := s.registryService.ResolveRepository(localName) if err != nil { return err } if _, err := s.poolAdd("push", repoInfo.LocalName); err != nil { return err } defer s.poolRemove("push", repoInfo.LocalName) endpoint, err := repoInfo.GetEndpoint(imagePushConfig.MetaHeaders) if err != nil { return err } // TODO(tiborvass): reuse client from endpoint? // Adds Docker-specific headers as well as user-specified headers (metaHeaders) tr := transport.NewTransport( registry.NewTransport(registry.NoTimeout, endpoint.IsSecure), registry.DockerHeaders(imagePushConfig.MetaHeaders)..., ) client := registry.HTTPClient(tr) r, err := registry.NewSession(client, imagePushConfig.AuthConfig, endpoint) if err != nil { return err } reposLen := 1 if imagePushConfig.Tag == "" { reposLen = len(s.Repositories[repoInfo.LocalName]) } imagePushConfig.OutStream.Write(sf.FormatStatus("", "The push refers to a repository [%s] (len: %d)", repoInfo.CanonicalName, reposLen)) // If it fails, try to get the repository localRepo, exists := s.Repositories[repoInfo.LocalName] if !exists { return fmt.Errorf("Repository does not exist: %s", repoInfo.LocalName) } if repoInfo.Index.Official || endpoint.Version == registry.APIVersion2 { err := s.pushV2Repository(r, localRepo, imagePushConfig.OutStream, repoInfo, imagePushConfig.Tag, sf) if err == nil { s.eventsService.Log("push", repoInfo.LocalName, "") return nil } if err != ErrV2RegistryUnavailable { return fmt.Errorf("Error pushing to registry: %s", err) } } if err := s.pushRepository(r, imagePushConfig.OutStream, repoInfo, localRepo, imagePushConfig.Tag, sf); err != nil { return err } s.eventsService.Log("push", repoInfo.LocalName, "") return nil }
func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConfig) error { var ( sf = streamformatter.NewJSONStreamFormatter() ) // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := s.registryService.ResolveRepository(image) if err != nil { return err } if err := validateRepoName(repoInfo.LocalName); err != nil { return err } c, err := s.poolAdd("pull", utils.ImageReference(repoInfo.LocalName, tag)) if err != nil { if c != nil { // Another pull of the same repository is already taking place; just wait for it to finish imagePullConfig.OutStream.Write(sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", repoInfo.LocalName)) <-c return nil } return err } defer s.poolRemove("pull", utils.ImageReference(repoInfo.LocalName, tag)) logName := repoInfo.LocalName if tag != "" { logName = utils.ImageReference(logName, tag) } // Attempt pulling official content from a provided v2 mirror if repoInfo.Index.Official { v2mirrorEndpoint, v2mirrorRepoInfo, err := configureV2Mirror(repoInfo, s.registryService) if err != nil { glog.Errorf("Error configuring mirrors: %s", err) return err } if v2mirrorEndpoint != nil { glog.V(1).Infof("Attempting to pull from v2 mirror: %s", v2mirrorEndpoint.URL) return s.pullFromV2Mirror(v2mirrorEndpoint, v2mirrorRepoInfo, imagePullConfig, tag, sf, logName) } } glog.V(1).Infof("pulling image from host %q with remote name %q", repoInfo.Index.Name, repoInfo.RemoteName) endpoint, err := repoInfo.GetEndpoint(imagePullConfig.MetaHeaders) if err != nil { return err } // TODO(tiborvass): reuse client from endpoint? // Adds Docker-specific headers as well as user-specified headers (metaHeaders) tr := transport.NewTransport( registry.NewTransport(registry.ReceiveTimeout, endpoint.IsSecure), registry.DockerHeaders(imagePullConfig.MetaHeaders)..., ) client := registry.HTTPClient(tr) r, err := registry.NewSession(client, imagePullConfig.AuthConfig, endpoint) if err != nil { return err } if len(repoInfo.Index.Mirrors) == 0 && (repoInfo.Index.Official || endpoint.Version == registry.APIVersion2) { if repoInfo.Official { s.trustService.UpdateBase() } glog.V(1).Infof("pulling v2 repository with local name %q", repoInfo.LocalName) if err := s.pullV2Repository(r, imagePullConfig.OutStream, repoInfo, tag, sf); err == nil { s.eventsService.Log("pull", logName, "") return nil } else if err != registry.ErrDoesNotExist && err != ErrV2RegistryUnavailable { glog.Errorf("Error from V2 registry: %s", err) } glog.V(1).Info("image does not exist on v2 registry, falling back to v1") } if utils.DigestReference(tag) { return fmt.Errorf("pulling with digest reference failed from v2 registry") } glog.V(1).Infof("pulling v1 repository with local name %q", repoInfo.LocalName) if err = s.pullRepository(r, imagePullConfig.OutStream, repoInfo, tag, sf); err != nil { return err } s.eventsService.Log("pull", logName, "") return nil }