| ... | ... |
@@ -55,6 +55,25 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf |
| 55 | 55 |
} |
| 56 | 56 |
defer s.poolRemove("pull", utils.ImageReference(repoInfo.LocalName, tag))
|
| 57 | 57 |
|
| 58 |
+ logName := repoInfo.LocalName |
|
| 59 |
+ if tag != "" {
|
|
| 60 |
+ logName = utils.ImageReference(logName, tag) |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ // Attempt pulling official content from a provided v2 mirror |
|
| 64 |
+ if repoInfo.Index.Official {
|
|
| 65 |
+ v2mirrorEndpoint, v2mirrorRepoInfo, err := configureV2Mirror(repoInfo, s.registryService) |
|
| 66 |
+ if err != nil {
|
|
| 67 |
+ logrus.Errorf("Error configuring mirrors: %s", err)
|
|
| 68 |
+ return err |
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ if v2mirrorEndpoint != nil {
|
|
| 72 |
+ logrus.Debugf("Attempting to pull from v2 mirror: %s", v2mirrorEndpoint.URL)
|
|
| 73 |
+ return s.pullFromV2Mirror(v2mirrorEndpoint, v2mirrorRepoInfo, imagePullConfig, tag, sf, logName) |
|
| 74 |
+ } |
|
| 75 |
+ } |
|
| 76 |
+ |
|
| 58 | 77 |
logrus.Debugf("pulling image from host %q with remote name %q", repoInfo.Index.Name, repoInfo.RemoteName)
|
| 59 | 78 |
|
| 60 | 79 |
endpoint, err := repoInfo.GetEndpoint(imagePullConfig.MetaHeaders) |
| ... | ... |
@@ -73,11 +92,6 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf |
| 73 | 73 |
return err |
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 |
- logName := repoInfo.LocalName |
|
| 77 |
- if tag != "" {
|
|
| 78 |
- logName = utils.ImageReference(logName, tag) |
|
| 79 |
- } |
|
| 80 |
- |
|
| 81 | 76 |
if len(repoInfo.Index.Mirrors) == 0 && (repoInfo.Index.Official || endpoint.Version == registry.APIVersion2) {
|
| 82 | 77 |
if repoInfo.Official {
|
| 83 | 78 |
s.trustService.UpdateBase() |
| ... | ... |
@@ -106,6 +120,91 @@ func (s *TagStore) Pull(image string, tag string, imagePullConfig *ImagePullConf |
| 106 | 106 |
s.eventsService.Log("pull", logName, "")
|
| 107 | 107 |
|
| 108 | 108 |
return nil |
| 109 |
+ |
|
| 110 |
+} |
|
| 111 |
+ |
|
| 112 |
+func makeMirrorRepoInfo(repoInfo *registry.RepositoryInfo, mirror string) *registry.RepositoryInfo {
|
|
| 113 |
+ mirrorRepo := ®istry.RepositoryInfo{
|
|
| 114 |
+ RemoteName: repoInfo.RemoteName, |
|
| 115 |
+ LocalName: repoInfo.LocalName, |
|
| 116 |
+ CanonicalName: repoInfo.CanonicalName, |
|
| 117 |
+ Official: false, |
|
| 118 |
+ |
|
| 119 |
+ Index: ®istry.IndexInfo{
|
|
| 120 |
+ Official: false, |
|
| 121 |
+ Secure: repoInfo.Index.Secure, |
|
| 122 |
+ Name: mirror, |
|
| 123 |
+ Mirrors: []string{},
|
|
| 124 |
+ }, |
|
| 125 |
+ } |
|
| 126 |
+ return mirrorRepo |
|
| 127 |
+} |
|
| 128 |
+ |
|
| 129 |
+func configureV2Mirror(repoInfo *registry.RepositoryInfo, s *registry.Service) (*registry.Endpoint, *registry.RepositoryInfo, error) {
|
|
| 130 |
+ mirrors := repoInfo.Index.Mirrors |
|
| 131 |
+ |
|
| 132 |
+ if len(mirrors) == 0 {
|
|
| 133 |
+ // no mirrors configured |
|
| 134 |
+ return nil, nil, nil |
|
| 135 |
+ } |
|
| 136 |
+ |
|
| 137 |
+ v1MirrorCount := 0 |
|
| 138 |
+ var v2MirrorEndpoint *registry.Endpoint |
|
| 139 |
+ var v2MirrorRepoInfo *registry.RepositoryInfo |
|
| 140 |
+ var lastErr error |
|
| 141 |
+ for _, mirror := range mirrors {
|
|
| 142 |
+ mirrorRepoInfo := makeMirrorRepoInfo(repoInfo, mirror) |
|
| 143 |
+ endpoint, err := registry.NewEndpoint(mirrorRepoInfo.Index, nil) |
|
| 144 |
+ if err != nil {
|
|
| 145 |
+ logrus.Errorf("Unable to create endpoint for %s: %s", mirror, err)
|
|
| 146 |
+ lastErr = err |
|
| 147 |
+ continue |
|
| 148 |
+ } |
|
| 149 |
+ if endpoint.Version == 2 {
|
|
| 150 |
+ if v2MirrorEndpoint == nil {
|
|
| 151 |
+ v2MirrorEndpoint = endpoint |
|
| 152 |
+ v2MirrorRepoInfo = mirrorRepoInfo |
|
| 153 |
+ } else {
|
|
| 154 |
+ // > 1 v2 mirrors given |
|
| 155 |
+ return nil, nil, fmt.Errorf("multiple v2 mirrors configured")
|
|
| 156 |
+ } |
|
| 157 |
+ } else {
|
|
| 158 |
+ v1MirrorCount++ |
|
| 159 |
+ } |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ if v1MirrorCount == len(mirrors) {
|
|
| 163 |
+ // OK, but mirrors are v1 |
|
| 164 |
+ return nil, nil, nil |
|
| 165 |
+ } |
|
| 166 |
+ if v2MirrorEndpoint != nil && v1MirrorCount == 0 {
|
|
| 167 |
+ // OK, 1 v2 mirror specified |
|
| 168 |
+ return v2MirrorEndpoint, v2MirrorRepoInfo, nil |
|
| 169 |
+ } |
|
| 170 |
+ if v2MirrorEndpoint != nil && v1MirrorCount > 0 {
|
|
| 171 |
+ lastErr = fmt.Errorf("v1 and v2 mirrors configured")
|
|
| 172 |
+ } |
|
| 173 |
+ return nil, nil, lastErr |
|
| 174 |
+} |
|
| 175 |
+ |
|
| 176 |
+func (s *TagStore) pullFromV2Mirror(mirrorEndpoint *registry.Endpoint, repoInfo *registry.RepositoryInfo, |
|
| 177 |
+ imagePullConfig *ImagePullConfig, tag string, sf *streamformatter.StreamFormatter, logName string) error {
|
|
| 178 |
+ |
|
| 179 |
+ tr := transport.NewTransport( |
|
| 180 |
+ registry.NewTransport(registry.ReceiveTimeout, mirrorEndpoint.IsSecure), |
|
| 181 |
+ registry.DockerHeaders(imagePullConfig.MetaHeaders)..., |
|
| 182 |
+ ) |
|
| 183 |
+ client := registry.HTTPClient(tr) |
|
| 184 |
+ mirrorSession, err := registry.NewSession(client, &cliconfig.AuthConfig{}, mirrorEndpoint)
|
|
| 185 |
+ if err != nil {
|
|
| 186 |
+ return err |
|
| 187 |
+ } |
|
| 188 |
+ logrus.Debugf("Pulling v2 repository with local name %q from %s", repoInfo.LocalName, mirrorEndpoint.URL)
|
|
| 189 |
+ if err := s.pullV2Repository(mirrorSession, imagePullConfig.OutStream, repoInfo, tag, sf); err != nil {
|
|
| 190 |
+ return err |
|
| 191 |
+ } |
|
| 192 |
+ s.eventsService.Log("pull", logName, "")
|
|
| 193 |
+ return nil |
|
| 109 | 194 |
} |
| 110 | 195 |
|
| 111 | 196 |
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 * |
| 185 | 185 |
var lastErr, err error |
| 186 | 186 |
var isDownloaded bool |
| 187 | 187 |
for _, ep := range repoInfo.Index.Mirrors {
|
| 188 |
+ // Ensure endpoint is v1 |
|
| 189 |
+ ep = ep + "v1/" |
|
| 188 | 190 |
out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, repoInfo.CanonicalName, ep), nil))
|
| 189 | 191 |
if isDownloaded, err = s.pullImage(r, out, img.ID, ep, repoData.Tokens, sf); err != nil {
|
| 190 | 192 |
// Don't report errors when pulling from mirrors. |
| ... | ... |
@@ -189,7 +189,7 @@ func ValidateMirror(val string) (string, error) {
|
| 189 | 189 |
return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
|
| 190 | 190 |
} |
| 191 | 191 |
|
| 192 |
- return fmt.Sprintf("%s://%s/v1/", uri.Scheme, uri.Host), nil
|
|
| 192 |
+ return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
|
|
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 | 195 |
// ValidateIndexName validates an index name. |
| ... | ... |
@@ -358,7 +358,9 @@ func (config *ServiceConfig) NewRepositoryInfo(reposName string) (*RepositoryInf |
| 358 | 358 |
// *TODO: Decouple index name from hostname (via registry configuration?) |
| 359 | 359 |
repoInfo.LocalName = repoInfo.Index.Name + "/" + repoInfo.RemoteName |
| 360 | 360 |
repoInfo.CanonicalName = repoInfo.LocalName |
| 361 |
+ |
|
| 361 | 362 |
} |
| 363 |
+ |
|
| 362 | 364 |
return repoInfo, nil |
| 363 | 365 |
} |
| 364 | 366 |
|