Преглед изворни кода

Merge pull request #13374 from RichardScothern/v2-mirror

V2 mirror support
Tibor Vass пре 10 година
родитељ
комит
2daede5a9c
2 измењених фајлова са 109 додато и 6 уклоњено
  1. 106 5
      graph/pull.go
  2. 3 1
      registry/config.go

+ 106 - 5
graph/pull.go

@@ -55,6 +55,25 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
 	}
 	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 {
+			logrus.Errorf("Error configuring mirrors: %s", err)
+			return err
+		}
+
+		if v2mirrorEndpoint != nil {
+			logrus.Debugf("Attempting to pull from v2 mirror: %s", v2mirrorEndpoint.URL)
+			return s.pullFromV2Mirror(v2mirrorEndpoint, v2mirrorRepoInfo, imagePullConfig, tag, sf, logName)
+		}
+	}
+
 	logrus.Debugf("pulling image from host %q with remote name %q", repoInfo.Index.Name, repoInfo.RemoteName)
 
 	endpoint, err := repoInfo.GetEndpoint(imagePullConfig.MetaHeaders)
@@ -73,11 +92,6 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
 		return err
 	}
 
-	logName := repoInfo.LocalName
-	if tag != "" {
-		logName = utils.ImageReference(logName, tag)
-	}
-
 	if len(repoInfo.Index.Mirrors) == 0 && (repoInfo.Index.Official || endpoint.Version == registry.APIVersion2) {
 		if repoInfo.Official {
 			s.trustService.UpdateBase()
@@ -106,6 +120,91 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf
 	s.eventsService.Log("pull", logName, "")
 
 	return nil
+
+}
+
+func makeMirrorRepoInfo(repoInfo *registry.RepositoryInfo, mirror string) *registry.RepositoryInfo {
+	mirrorRepo := &registry.RepositoryInfo{
+		RemoteName:    repoInfo.RemoteName,
+		LocalName:     repoInfo.LocalName,
+		CanonicalName: repoInfo.CanonicalName,
+		Official:      false,
+
+		Index: &registry.IndexInfo{
+			Official: false,
+			Secure:   repoInfo.Index.Secure,
+			Name:     mirror,
+			Mirrors:  []string{},
+		},
+	}
+	return mirrorRepo
+}
+
+func configureV2Mirror(repoInfo *registry.RepositoryInfo, s *registry.Service) (*registry.Endpoint, *registry.RepositoryInfo, error) {
+	mirrors := repoInfo.Index.Mirrors
+
+	if len(mirrors) == 0 {
+		// no mirrors configured
+		return nil, nil, nil
+	}
+
+	v1MirrorCount := 0
+	var v2MirrorEndpoint *registry.Endpoint
+	var v2MirrorRepoInfo *registry.RepositoryInfo
+	var lastErr error
+	for _, mirror := range mirrors {
+		mirrorRepoInfo := makeMirrorRepoInfo(repoInfo, mirror)
+		endpoint, err := registry.NewEndpoint(mirrorRepoInfo.Index, nil)
+		if err != nil {
+			logrus.Errorf("Unable to create endpoint for %s: %s", mirror, err)
+			lastErr = err
+			continue
+		}
+		if endpoint.Version == 2 {
+			if v2MirrorEndpoint == nil {
+				v2MirrorEndpoint = endpoint
+				v2MirrorRepoInfo = mirrorRepoInfo
+			} else {
+				// > 1 v2 mirrors given
+				return nil, nil, fmt.Errorf("multiple v2 mirrors configured")
+			}
+		} else {
+			v1MirrorCount++
+		}
+	}
+
+	if v1MirrorCount == len(mirrors) {
+		// OK, but mirrors are v1
+		return nil, nil, nil
+	}
+	if v2MirrorEndpoint != nil && v1MirrorCount == 0 {
+		// OK, 1 v2 mirror specified
+		return v2MirrorEndpoint, v2MirrorRepoInfo, nil
+	}
+	if v2MirrorEndpoint != nil && v1MirrorCount > 0 {
+		lastErr = fmt.Errorf("v1 and v2 mirrors configured")
+	}
+	return nil, nil, lastErr
+}
+
+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
+	}
+	logrus.Debugf("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
 }
 
 func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, repoInfo *registry.RepositoryInfo, askedTag string, sf *streamformatter.StreamFormatter) error {
@@ -185,6 +284,8 @@ func (s *TagStore) pullRepository(r *registry.Session, out io.Writer, repoInfo *
 			var lastErr, err error
 			var isDownloaded bool
 			for _, ep := range repoInfo.Index.Mirrors {
+				// Ensure endpoint is v1
+				ep = ep + "v1/"
 				out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, repoInfo.CanonicalName, ep), nil))
 				if isDownloaded, err = s.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
 					// Don't report errors when pulling from mirrors.

+ 3 - 1
registry/config.go

@@ -189,7 +189,7 @@ func ValidateMirror(val string) (string, error) {
 		return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
 	}
 
-	return fmt.Sprintf("%s://%s/v1/", uri.Scheme, uri.Host), nil
+	return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
 }
 
 // ValidateIndexName validates an index name.
@@ -358,7 +358,9 @@ func (config *ServiceConfig) NewRepositoryInfo(reposName string) (*RepositoryInf
 		// *TODO: Decouple index name from hostname (via registry configuration?)
 		repoInfo.LocalName = repoInfo.Index.Name + "/" + repoInfo.RemoteName
 		repoInfo.CanonicalName = repoInfo.LocalName
+
 	}
+
 	return repoInfo, nil
 }