Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit 53dad9f0274fcc1ec742f9411142382c83d08ff9)
Signed-off-by: Tibor Vass <tibor@docker.com>
| ... | ... |
@@ -83,13 +83,6 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) error {
|
| 83 | 83 |
|
| 84 | 84 |
flags.IntVar(&conf.NetworkControlPlaneMTU, "network-control-plane-mtu", config.DefaultNetworkMtu, "Network Control plane MTU") |
| 85 | 85 |
|
| 86 |
- // "--deprecated-key-path" is to allow configuration of the key used |
|
| 87 |
- // for the daemon ID and the deprecated image signing. It was never |
|
| 88 |
- // exposed as a command line option but is added here to allow |
|
| 89 |
- // overriding the default path in configuration. |
|
| 90 |
- flags.Var(opts.NewQuotedString(&conf.TrustKeyPath), "deprecated-key-path", "Path to key file for ID and image signing") |
|
| 91 |
- flags.MarkHidden("deprecated-key-path")
|
|
| 92 |
- |
|
| 93 | 86 |
conf.MaxConcurrentDownloads = &maxConcurrentDownloads |
| 94 | 87 |
conf.MaxConcurrentUploads = &maxConcurrentUploads |
| 95 | 88 |
return nil |
| ... | ... |
@@ -103,10 +96,4 @@ func installRegistryServiceFlags(options *registry.ServiceOptions, flags *pflag. |
| 103 | 103 |
flags.Var(ana, "allow-nondistributable-artifacts", "Allow push of nondistributable artifacts to registry") |
| 104 | 104 |
flags.Var(mirrors, "registry-mirror", "Preferred Docker registry mirror") |
| 105 | 105 |
flags.Var(insecureRegistries, "insecure-registry", "Enable insecure registry communication") |
| 106 |
- |
|
| 107 |
- if runtime.GOOS != "windows" {
|
|
| 108 |
- // TODO: Remove this flag after 3 release cycles (18.03) |
|
| 109 |
- flags.BoolVar(&options.V2Only, "disable-legacy-registry", true, "Disable contacting legacy registries") |
|
| 110 |
- flags.MarkHidden("disable-legacy-registry")
|
|
| 111 |
- } |
|
| 112 | 106 |
} |
| ... | ... |
@@ -454,17 +454,6 @@ func loadDaemonCliConfig(opts *daemonOptions) (*config.Config, error) {
|
| 454 | 454 |
return nil, err |
| 455 | 455 |
} |
| 456 | 456 |
|
| 457 |
- if runtime.GOOS != "windows" {
|
|
| 458 |
- if flags.Changed("disable-legacy-registry") {
|
|
| 459 |
- // TODO: Remove this error after 3 release cycles (18.03) |
|
| 460 |
- return nil, errors.New("ERROR: The '--disable-legacy-registry' flag has been removed. Interacting with legacy (v1) registries is no longer supported")
|
|
| 461 |
- } |
|
| 462 |
- if !conf.V2Only {
|
|
| 463 |
- // TODO: Remove this error after 3 release cycles (18.03) |
|
| 464 |
- return nil, errors.New("ERROR: The 'disable-legacy-registry' configuration option has been removed. Interacting with legacy (v1) registries is no longer supported")
|
|
| 465 |
- } |
|
| 466 |
- } |
|
| 467 |
- |
|
| 468 | 457 |
if flags.Changed("graph") {
|
| 469 | 458 |
logrus.Warnf(`The "-g / --graph" flag is deprecated. Please use "--data-root" instead`) |
| 470 | 459 |
} |
| ... | ... |
@@ -8,7 +8,6 @@ import ( |
| 8 | 8 |
"io/ioutil" |
| 9 | 9 |
"os" |
| 10 | 10 |
"reflect" |
| 11 |
- "runtime" |
|
| 12 | 11 |
"strings" |
| 13 | 12 |
"sync" |
| 14 | 13 |
|
| ... | ... |
@@ -246,10 +245,6 @@ func New() *Config {
|
| 246 | 246 |
config := Config{}
|
| 247 | 247 |
config.LogConfig.Config = make(map[string]string) |
| 248 | 248 |
config.ClusterOpts = make(map[string]string) |
| 249 |
- |
|
| 250 |
- if runtime.GOOS != "linux" {
|
|
| 251 |
- config.V2Only = true |
|
| 252 |
- } |
|
| 253 | 249 |
return &config |
| 254 | 250 |
} |
| 255 | 251 |
|
| ... | ... |
@@ -39,12 +39,7 @@ func newPuller(endpoint registry.APIEndpoint, repoInfo *registry.RepositoryInfo, |
| 39 | 39 |
repoInfo: repoInfo, |
| 40 | 40 |
}, nil |
| 41 | 41 |
case registry.APIVersion1: |
| 42 |
- return &v1Puller{
|
|
| 43 |
- v1IDService: metadata.NewV1IDService(imagePullConfig.MetadataStore), |
|
| 44 |
- endpoint: endpoint, |
|
| 45 |
- config: imagePullConfig, |
|
| 46 |
- repoInfo: repoInfo, |
|
| 47 |
- }, nil |
|
| 42 |
+ return nil, fmt.Errorf("protocol version %d no longer supported. Please contact admins of registry %s", endpoint.Version, endpoint.URL)
|
|
| 48 | 43 |
} |
| 49 | 44 |
return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
|
| 50 | 45 |
} |
| 51 | 46 |
deleted file mode 100644 |
| ... | ... |
@@ -1,365 +0,0 @@ |
| 1 |
-package distribution // import "github.com/docker/docker/distribution" |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "context" |
|
| 5 |
- "errors" |
|
| 6 |
- "fmt" |
|
| 7 |
- "io" |
|
| 8 |
- "io/ioutil" |
|
| 9 |
- "net" |
|
| 10 |
- "net/url" |
|
| 11 |
- "os" |
|
| 12 |
- "strings" |
|
| 13 |
- "time" |
|
| 14 |
- |
|
| 15 |
- "github.com/docker/distribution/reference" |
|
| 16 |
- "github.com/docker/distribution/registry/client/transport" |
|
| 17 |
- "github.com/docker/docker/distribution/metadata" |
|
| 18 |
- "github.com/docker/docker/distribution/xfer" |
|
| 19 |
- "github.com/docker/docker/dockerversion" |
|
| 20 |
- "github.com/docker/docker/image" |
|
| 21 |
- "github.com/docker/docker/image/v1" |
|
| 22 |
- "github.com/docker/docker/layer" |
|
| 23 |
- "github.com/docker/docker/pkg/ioutils" |
|
| 24 |
- "github.com/docker/docker/pkg/progress" |
|
| 25 |
- "github.com/docker/docker/pkg/stringid" |
|
| 26 |
- "github.com/docker/docker/registry" |
|
| 27 |
- specs "github.com/opencontainers/image-spec/specs-go/v1" |
|
| 28 |
- "github.com/sirupsen/logrus" |
|
| 29 |
-) |
|
| 30 |
- |
|
| 31 |
-type v1Puller struct {
|
|
| 32 |
- v1IDService *metadata.V1IDService |
|
| 33 |
- endpoint registry.APIEndpoint |
|
| 34 |
- config *ImagePullConfig |
|
| 35 |
- repoInfo *registry.RepositoryInfo |
|
| 36 |
- session *registry.Session |
|
| 37 |
-} |
|
| 38 |
- |
|
| 39 |
-func (p *v1Puller) Pull(ctx context.Context, ref reference.Named, _ *specs.Platform) error {
|
|
| 40 |
- if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
|
| 41 |
- // Allowing fallback, because HTTPS v1 is before HTTP v2 |
|
| 42 |
- return fallbackError{err: ErrNoSupport{Err: errors.New("Cannot pull by digest with v1 registry")}}
|
|
| 43 |
- } |
|
| 44 |
- |
|
| 45 |
- tlsConfig, err := p.config.RegistryService.TLSConfig(p.repoInfo.Index.Name) |
|
| 46 |
- if err != nil {
|
|
| 47 |
- return err |
|
| 48 |
- } |
|
| 49 |
- // Adds Docker-specific headers as well as user-specified headers (metaHeaders) |
|
| 50 |
- tr := transport.NewTransport( |
|
| 51 |
- // TODO(tiborvass): was ReceiveTimeout |
|
| 52 |
- registry.NewTransport(tlsConfig), |
|
| 53 |
- registry.Headers(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders)..., |
|
| 54 |
- ) |
|
| 55 |
- client := registry.HTTPClient(tr) |
|
| 56 |
- v1Endpoint := p.endpoint.ToV1Endpoint(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders) |
|
| 57 |
- p.session, err = registry.NewSession(client, p.config.AuthConfig, v1Endpoint) |
|
| 58 |
- if err != nil {
|
|
| 59 |
- // TODO(dmcgowan): Check if should fallback |
|
| 60 |
- logrus.Debugf("Fallback from error: %s", err)
|
|
| 61 |
- return fallbackError{err: err}
|
|
| 62 |
- } |
|
| 63 |
- if err := p.pullRepository(ctx, ref); err != nil {
|
|
| 64 |
- // TODO(dmcgowan): Check if should fallback |
|
| 65 |
- return err |
|
| 66 |
- } |
|
| 67 |
- progress.Message(p.config.ProgressOutput, "", p.repoInfo.Name.Name()+": this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.") |
|
| 68 |
- |
|
| 69 |
- return nil |
|
| 70 |
-} |
|
| 71 |
- |
|
| 72 |
-func (p *v1Puller) pullRepository(ctx context.Context, ref reference.Named) error {
|
|
| 73 |
- progress.Message(p.config.ProgressOutput, "", "Pulling repository "+p.repoInfo.Name.Name()) |
|
| 74 |
- |
|
| 75 |
- tagged, isTagged := ref.(reference.NamedTagged) |
|
| 76 |
- |
|
| 77 |
- repoData, err := p.session.GetRepositoryData(p.repoInfo.Name) |
|
| 78 |
- if err != nil {
|
|
| 79 |
- if strings.Contains(err.Error(), "HTTP code: 404") {
|
|
| 80 |
- if isTagged {
|
|
| 81 |
- return fmt.Errorf("Error: image %s:%s not found", reference.Path(p.repoInfo.Name), tagged.Tag())
|
|
| 82 |
- } |
|
| 83 |
- return fmt.Errorf("Error: image %s not found", reference.Path(p.repoInfo.Name))
|
|
| 84 |
- } |
|
| 85 |
- // Unexpected HTTP error |
|
| 86 |
- return err |
|
| 87 |
- } |
|
| 88 |
- |
|
| 89 |
- logrus.Debug("Retrieving the tag list")
|
|
| 90 |
- var tagsList map[string]string |
|
| 91 |
- if !isTagged {
|
|
| 92 |
- tagsList, err = p.session.GetRemoteTags(repoData.Endpoints, p.repoInfo.Name) |
|
| 93 |
- } else {
|
|
| 94 |
- var tagID string |
|
| 95 |
- tagsList = make(map[string]string) |
|
| 96 |
- tagID, err = p.session.GetRemoteTag(repoData.Endpoints, p.repoInfo.Name, tagged.Tag()) |
|
| 97 |
- if err == registry.ErrRepoNotFound {
|
|
| 98 |
- return fmt.Errorf("Tag %s not found in repository %s", tagged.Tag(), p.repoInfo.Name.Name())
|
|
| 99 |
- } |
|
| 100 |
- tagsList[tagged.Tag()] = tagID |
|
| 101 |
- } |
|
| 102 |
- if err != nil {
|
|
| 103 |
- logrus.Errorf("unable to get remote tags: %s", err)
|
|
| 104 |
- return err |
|
| 105 |
- } |
|
| 106 |
- |
|
| 107 |
- for tag, id := range tagsList {
|
|
| 108 |
- repoData.ImgList[id] = ®istry.ImgData{
|
|
| 109 |
- ID: id, |
|
| 110 |
- Tag: tag, |
|
| 111 |
- Checksum: "", |
|
| 112 |
- } |
|
| 113 |
- } |
|
| 114 |
- |
|
| 115 |
- layersDownloaded := false |
|
| 116 |
- for _, imgData := range repoData.ImgList {
|
|
| 117 |
- if isTagged && imgData.Tag != tagged.Tag() {
|
|
| 118 |
- continue |
|
| 119 |
- } |
|
| 120 |
- |
|
| 121 |
- err := p.downloadImage(ctx, repoData, imgData, &layersDownloaded) |
|
| 122 |
- if err != nil {
|
|
| 123 |
- return err |
|
| 124 |
- } |
|
| 125 |
- } |
|
| 126 |
- |
|
| 127 |
- writeStatus(reference.FamiliarString(ref), p.config.ProgressOutput, layersDownloaded) |
|
| 128 |
- return nil |
|
| 129 |
-} |
|
| 130 |
- |
|
| 131 |
-func (p *v1Puller) downloadImage(ctx context.Context, repoData *registry.RepositoryData, img *registry.ImgData, layersDownloaded *bool) error {
|
|
| 132 |
- if img.Tag == "" {
|
|
| 133 |
- logrus.Debugf("Image (id: %s) present in this repository but untagged, skipping", img.ID)
|
|
| 134 |
- return nil |
|
| 135 |
- } |
|
| 136 |
- |
|
| 137 |
- localNameRef, err := reference.WithTag(p.repoInfo.Name, img.Tag) |
|
| 138 |
- if err != nil {
|
|
| 139 |
- retErr := fmt.Errorf("Image (id: %s) has invalid tag: %s", img.ID, img.Tag)
|
|
| 140 |
- logrus.Debug(retErr.Error()) |
|
| 141 |
- return retErr |
|
| 142 |
- } |
|
| 143 |
- |
|
| 144 |
- if err := v1.ValidateID(img.ID); err != nil {
|
|
| 145 |
- return err |
|
| 146 |
- } |
|
| 147 |
- |
|
| 148 |
- progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s", img.Tag, p.repoInfo.Name.Name()) |
|
| 149 |
- success := false |
|
| 150 |
- var lastErr error |
|
| 151 |
- for _, ep := range p.repoInfo.Index.Mirrors {
|
|
| 152 |
- ep += "v1/" |
|
| 153 |
- progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s, mirror: %s", img.Tag, p.repoInfo.Name.Name(), ep))
|
|
| 154 |
- if err = p.pullImage(ctx, img.ID, ep, localNameRef, layersDownloaded); err != nil {
|
|
| 155 |
- // Don't report errors when pulling from mirrors. |
|
| 156 |
- logrus.Debugf("Error pulling image (%s) from %s, mirror: %s, %s", img.Tag, p.repoInfo.Name.Name(), ep, err)
|
|
| 157 |
- continue |
|
| 158 |
- } |
|
| 159 |
- success = true |
|
| 160 |
- break |
|
| 161 |
- } |
|
| 162 |
- if !success {
|
|
| 163 |
- for _, ep := range repoData.Endpoints {
|
|
| 164 |
- progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Pulling image (%s) from %s, endpoint: %s", img.Tag, p.repoInfo.Name.Name(), ep) |
|
| 165 |
- if err = p.pullImage(ctx, img.ID, ep, localNameRef, layersDownloaded); err != nil {
|
|
| 166 |
- // It's not ideal that only the last error is returned, it would be better to concatenate the errors. |
|
| 167 |
- // As the error is also given to the output stream the user will see the error. |
|
| 168 |
- lastErr = err |
|
| 169 |
- progress.Updatef(p.config.ProgressOutput, stringid.TruncateID(img.ID), "Error pulling image (%s) from %s, endpoint: %s, %s", img.Tag, p.repoInfo.Name.Name(), ep, err) |
|
| 170 |
- continue |
|
| 171 |
- } |
|
| 172 |
- success = true |
|
| 173 |
- break |
|
| 174 |
- } |
|
| 175 |
- } |
|
| 176 |
- if !success {
|
|
| 177 |
- err := fmt.Errorf("Error pulling image (%s) from %s, %v", img.Tag, p.repoInfo.Name.Name(), lastErr)
|
|
| 178 |
- progress.Update(p.config.ProgressOutput, stringid.TruncateID(img.ID), err.Error()) |
|
| 179 |
- return err |
|
| 180 |
- } |
|
| 181 |
- return nil |
|
| 182 |
-} |
|
| 183 |
- |
|
| 184 |
-func (p *v1Puller) pullImage(ctx context.Context, v1ID, endpoint string, localNameRef reference.Named, layersDownloaded *bool) (err error) {
|
|
| 185 |
- var history []string |
|
| 186 |
- history, err = p.session.GetRemoteHistory(v1ID, endpoint) |
|
| 187 |
- if err != nil {
|
|
| 188 |
- return err |
|
| 189 |
- } |
|
| 190 |
- if len(history) < 1 {
|
|
| 191 |
- return fmt.Errorf("empty history for image %s", v1ID)
|
|
| 192 |
- } |
|
| 193 |
- progress.Update(p.config.ProgressOutput, stringid.TruncateID(v1ID), "Pulling dependent layers") |
|
| 194 |
- |
|
| 195 |
- var ( |
|
| 196 |
- descriptors []xfer.DownloadDescriptor |
|
| 197 |
- newHistory []image.History |
|
| 198 |
- imgJSON []byte |
|
| 199 |
- imgSize int64 |
|
| 200 |
- ) |
|
| 201 |
- |
|
| 202 |
- // Iterate over layers, in order from bottom-most to top-most. Download |
|
| 203 |
- // config for all layers and create descriptors. |
|
| 204 |
- for i := len(history) - 1; i >= 0; i-- {
|
|
| 205 |
- v1LayerID := history[i] |
|
| 206 |
- imgJSON, imgSize, err = p.downloadLayerConfig(v1LayerID, endpoint) |
|
| 207 |
- if err != nil {
|
|
| 208 |
- return err |
|
| 209 |
- } |
|
| 210 |
- |
|
| 211 |
- // Create a new-style config from the legacy configs |
|
| 212 |
- h, err := v1.HistoryFromConfig(imgJSON, false) |
|
| 213 |
- if err != nil {
|
|
| 214 |
- return err |
|
| 215 |
- } |
|
| 216 |
- newHistory = append(newHistory, h) |
|
| 217 |
- |
|
| 218 |
- layerDescriptor := &v1LayerDescriptor{
|
|
| 219 |
- v1LayerID: v1LayerID, |
|
| 220 |
- indexName: p.repoInfo.Index.Name, |
|
| 221 |
- endpoint: endpoint, |
|
| 222 |
- v1IDService: p.v1IDService, |
|
| 223 |
- layersDownloaded: layersDownloaded, |
|
| 224 |
- layerSize: imgSize, |
|
| 225 |
- session: p.session, |
|
| 226 |
- } |
|
| 227 |
- |
|
| 228 |
- descriptors = append(descriptors, layerDescriptor) |
|
| 229 |
- } |
|
| 230 |
- |
|
| 231 |
- rootFS := image.NewRootFS() |
|
| 232 |
- resultRootFS, release, err := p.config.DownloadManager.Download(ctx, *rootFS, "", descriptors, p.config.ProgressOutput) |
|
| 233 |
- if err != nil {
|
|
| 234 |
- return err |
|
| 235 |
- } |
|
| 236 |
- defer release() |
|
| 237 |
- |
|
| 238 |
- config, err := v1.MakeConfigFromV1Config(imgJSON, &resultRootFS, newHistory) |
|
| 239 |
- if err != nil {
|
|
| 240 |
- return err |
|
| 241 |
- } |
|
| 242 |
- |
|
| 243 |
- imageID, err := p.config.ImageStore.Put(config) |
|
| 244 |
- if err != nil {
|
|
| 245 |
- return err |
|
| 246 |
- } |
|
| 247 |
- |
|
| 248 |
- if p.config.ReferenceStore != nil {
|
|
| 249 |
- if err := p.config.ReferenceStore.AddTag(localNameRef, imageID, true); err != nil {
|
|
| 250 |
- return err |
|
| 251 |
- } |
|
| 252 |
- } |
|
| 253 |
- |
|
| 254 |
- return nil |
|
| 255 |
-} |
|
| 256 |
- |
|
| 257 |
-func (p *v1Puller) downloadLayerConfig(v1LayerID, endpoint string) (imgJSON []byte, imgSize int64, err error) {
|
|
| 258 |
- progress.Update(p.config.ProgressOutput, stringid.TruncateID(v1LayerID), "Pulling metadata") |
|
| 259 |
- |
|
| 260 |
- retries := 5 |
|
| 261 |
- for j := 1; j <= retries; j++ {
|
|
| 262 |
- imgJSON, imgSize, err := p.session.GetRemoteImageJSON(v1LayerID, endpoint) |
|
| 263 |
- if err != nil && j == retries {
|
|
| 264 |
- progress.Update(p.config.ProgressOutput, stringid.TruncateID(v1LayerID), "Error pulling layer metadata") |
|
| 265 |
- return nil, 0, err |
|
| 266 |
- } else if err != nil {
|
|
| 267 |
- time.Sleep(time.Duration(j) * 500 * time.Millisecond) |
|
| 268 |
- continue |
|
| 269 |
- } |
|
| 270 |
- |
|
| 271 |
- return imgJSON, imgSize, nil |
|
| 272 |
- } |
|
| 273 |
- |
|
| 274 |
- // not reached |
|
| 275 |
- return nil, 0, nil |
|
| 276 |
-} |
|
| 277 |
- |
|
| 278 |
-type v1LayerDescriptor struct {
|
|
| 279 |
- v1LayerID string |
|
| 280 |
- indexName string |
|
| 281 |
- endpoint string |
|
| 282 |
- v1IDService *metadata.V1IDService |
|
| 283 |
- layersDownloaded *bool |
|
| 284 |
- layerSize int64 |
|
| 285 |
- session *registry.Session |
|
| 286 |
- tmpFile *os.File |
|
| 287 |
-} |
|
| 288 |
- |
|
| 289 |
-func (ld *v1LayerDescriptor) Key() string {
|
|
| 290 |
- return "v1:" + ld.v1LayerID |
|
| 291 |
-} |
|
| 292 |
- |
|
| 293 |
-func (ld *v1LayerDescriptor) ID() string {
|
|
| 294 |
- return stringid.TruncateID(ld.v1LayerID) |
|
| 295 |
-} |
|
| 296 |
- |
|
| 297 |
-func (ld *v1LayerDescriptor) DiffID() (layer.DiffID, error) {
|
|
| 298 |
- return ld.v1IDService.Get(ld.v1LayerID, ld.indexName) |
|
| 299 |
-} |
|
| 300 |
- |
|
| 301 |
-func (ld *v1LayerDescriptor) Download(ctx context.Context, progressOutput progress.Output) (io.ReadCloser, int64, error) {
|
|
| 302 |
- progress.Update(progressOutput, ld.ID(), "Pulling fs layer") |
|
| 303 |
- layerReader, err := ld.session.GetRemoteImageLayer(ld.v1LayerID, ld.endpoint, ld.layerSize) |
|
| 304 |
- if err != nil {
|
|
| 305 |
- progress.Update(progressOutput, ld.ID(), "Error pulling dependent layers") |
|
| 306 |
- if uerr, ok := err.(*url.Error); ok {
|
|
| 307 |
- err = uerr.Err |
|
| 308 |
- } |
|
| 309 |
- if terr, ok := err.(net.Error); ok && terr.Timeout() {
|
|
| 310 |
- return nil, 0, err |
|
| 311 |
- } |
|
| 312 |
- return nil, 0, xfer.DoNotRetry{Err: err}
|
|
| 313 |
- } |
|
| 314 |
- *ld.layersDownloaded = true |
|
| 315 |
- |
|
| 316 |
- ld.tmpFile, err = ioutil.TempFile("", "GetImageBlob")
|
|
| 317 |
- if err != nil {
|
|
| 318 |
- layerReader.Close() |
|
| 319 |
- return nil, 0, err |
|
| 320 |
- } |
|
| 321 |
- |
|
| 322 |
- reader := progress.NewProgressReader(ioutils.NewCancelReadCloser(ctx, layerReader), progressOutput, ld.layerSize, ld.ID(), "Downloading") |
|
| 323 |
- defer reader.Close() |
|
| 324 |
- |
|
| 325 |
- _, err = io.Copy(ld.tmpFile, reader) |
|
| 326 |
- if err != nil {
|
|
| 327 |
- ld.Close() |
|
| 328 |
- return nil, 0, err |
|
| 329 |
- } |
|
| 330 |
- |
|
| 331 |
- progress.Update(progressOutput, ld.ID(), "Download complete") |
|
| 332 |
- |
|
| 333 |
- logrus.Debugf("Downloaded %s to tempfile %s", ld.ID(), ld.tmpFile.Name())
|
|
| 334 |
- |
|
| 335 |
- ld.tmpFile.Seek(0, 0) |
|
| 336 |
- |
|
| 337 |
- // hand off the temporary file to the download manager, so it will only |
|
| 338 |
- // be closed once |
|
| 339 |
- tmpFile := ld.tmpFile |
|
| 340 |
- ld.tmpFile = nil |
|
| 341 |
- |
|
| 342 |
- return ioutils.NewReadCloserWrapper(tmpFile, func() error {
|
|
| 343 |
- tmpFile.Close() |
|
| 344 |
- err := os.RemoveAll(tmpFile.Name()) |
|
| 345 |
- if err != nil {
|
|
| 346 |
- logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
|
|
| 347 |
- } |
|
| 348 |
- return err |
|
| 349 |
- }), ld.layerSize, nil |
|
| 350 |
-} |
|
| 351 |
- |
|
| 352 |
-func (ld *v1LayerDescriptor) Close() {
|
|
| 353 |
- if ld.tmpFile != nil {
|
|
| 354 |
- ld.tmpFile.Close() |
|
| 355 |
- if err := os.RemoveAll(ld.tmpFile.Name()); err != nil {
|
|
| 356 |
- logrus.Errorf("Failed to remove temp file: %s", ld.tmpFile.Name())
|
|
| 357 |
- } |
|
| 358 |
- ld.tmpFile = nil |
|
| 359 |
- } |
|
| 360 |
-} |
|
| 361 |
- |
|
| 362 |
-func (ld *v1LayerDescriptor) Registered(diffID layer.DiffID) {
|
|
| 363 |
- // Cache mapping from this layer's DiffID to the blobsum |
|
| 364 |
- ld.v1IDService.Set(ld.v1LayerID, ld.indexName, diffID) |
|
| 365 |
-} |
| ... | ... |
@@ -41,13 +41,7 @@ func NewPusher(ref reference.Named, endpoint registry.APIEndpoint, repoInfo *reg |
| 41 | 41 |
config: imagePushConfig, |
| 42 | 42 |
}, nil |
| 43 | 43 |
case registry.APIVersion1: |
| 44 |
- return &v1Pusher{
|
|
| 45 |
- v1IDService: metadata.NewV1IDService(imagePushConfig.MetadataStore), |
|
| 46 |
- ref: ref, |
|
| 47 |
- endpoint: endpoint, |
|
| 48 |
- repoInfo: repoInfo, |
|
| 49 |
- config: imagePushConfig, |
|
| 50 |
- }, nil |
|
| 44 |
+ return nil, fmt.Errorf("protocol version %d no longer supported. Please contact admins of registry %s", endpoint.Version, endpoint.URL)
|
|
| 51 | 45 |
} |
| 52 | 46 |
return nil, fmt.Errorf("unknown version %d for registry %s", endpoint.Version, endpoint.URL)
|
| 53 | 47 |
} |
| 54 | 48 |
deleted file mode 100644 |
| ... | ... |
@@ -1,457 +0,0 @@ |
| 1 |
-package distribution // import "github.com/docker/docker/distribution" |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "context" |
|
| 5 |
- "fmt" |
|
| 6 |
- "sync" |
|
| 7 |
- |
|
| 8 |
- "github.com/docker/distribution/reference" |
|
| 9 |
- "github.com/docker/distribution/registry/client/transport" |
|
| 10 |
- "github.com/docker/docker/distribution/metadata" |
|
| 11 |
- "github.com/docker/docker/dockerversion" |
|
| 12 |
- "github.com/docker/docker/image" |
|
| 13 |
- "github.com/docker/docker/image/v1" |
|
| 14 |
- "github.com/docker/docker/layer" |
|
| 15 |
- "github.com/docker/docker/pkg/ioutils" |
|
| 16 |
- "github.com/docker/docker/pkg/progress" |
|
| 17 |
- "github.com/docker/docker/pkg/stringid" |
|
| 18 |
- "github.com/docker/docker/pkg/system" |
|
| 19 |
- "github.com/docker/docker/registry" |
|
| 20 |
- "github.com/opencontainers/go-digest" |
|
| 21 |
- "github.com/sirupsen/logrus" |
|
| 22 |
-) |
|
| 23 |
- |
|
| 24 |
-type v1Pusher struct {
|
|
| 25 |
- v1IDService *metadata.V1IDService |
|
| 26 |
- endpoint registry.APIEndpoint |
|
| 27 |
- ref reference.Named |
|
| 28 |
- repoInfo *registry.RepositoryInfo |
|
| 29 |
- config *ImagePushConfig |
|
| 30 |
- session *registry.Session |
|
| 31 |
-} |
|
| 32 |
- |
|
| 33 |
-func (p *v1Pusher) Push(ctx context.Context) error {
|
|
| 34 |
- tlsConfig, err := p.config.RegistryService.TLSConfig(p.repoInfo.Index.Name) |
|
| 35 |
- if err != nil {
|
|
| 36 |
- return err |
|
| 37 |
- } |
|
| 38 |
- // Adds Docker-specific headers as well as user-specified headers (metaHeaders) |
|
| 39 |
- tr := transport.NewTransport( |
|
| 40 |
- // TODO(tiborvass): was NoTimeout |
|
| 41 |
- registry.NewTransport(tlsConfig), |
|
| 42 |
- registry.Headers(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders)..., |
|
| 43 |
- ) |
|
| 44 |
- client := registry.HTTPClient(tr) |
|
| 45 |
- v1Endpoint := p.endpoint.ToV1Endpoint(dockerversion.DockerUserAgent(ctx), p.config.MetaHeaders) |
|
| 46 |
- p.session, err = registry.NewSession(client, p.config.AuthConfig, v1Endpoint) |
|
| 47 |
- if err != nil {
|
|
| 48 |
- // TODO(dmcgowan): Check if should fallback |
|
| 49 |
- return fallbackError{err: err}
|
|
| 50 |
- } |
|
| 51 |
- if err := p.pushRepository(ctx); err != nil {
|
|
| 52 |
- // TODO(dmcgowan): Check if should fallback |
|
| 53 |
- return err |
|
| 54 |
- } |
|
| 55 |
- return nil |
|
| 56 |
-} |
|
| 57 |
- |
|
| 58 |
-// v1Image exposes the configuration, filesystem layer ID, and a v1 ID for an |
|
| 59 |
-// image being pushed to a v1 registry. |
|
| 60 |
-type v1Image interface {
|
|
| 61 |
- Config() []byte |
|
| 62 |
- Layer() layer.Layer |
|
| 63 |
- V1ID() string |
|
| 64 |
-} |
|
| 65 |
- |
|
| 66 |
-type v1ImageCommon struct {
|
|
| 67 |
- layer layer.Layer |
|
| 68 |
- config []byte |
|
| 69 |
- v1ID string |
|
| 70 |
-} |
|
| 71 |
- |
|
| 72 |
-func (common *v1ImageCommon) Config() []byte {
|
|
| 73 |
- return common.config |
|
| 74 |
-} |
|
| 75 |
- |
|
| 76 |
-func (common *v1ImageCommon) V1ID() string {
|
|
| 77 |
- return common.v1ID |
|
| 78 |
-} |
|
| 79 |
- |
|
| 80 |
-func (common *v1ImageCommon) Layer() layer.Layer {
|
|
| 81 |
- return common.layer |
|
| 82 |
-} |
|
| 83 |
- |
|
| 84 |
-// v1TopImage defines a runnable (top layer) image being pushed to a v1 |
|
| 85 |
-// registry. |
|
| 86 |
-type v1TopImage struct {
|
|
| 87 |
- v1ImageCommon |
|
| 88 |
- imageID image.ID |
|
| 89 |
-} |
|
| 90 |
- |
|
| 91 |
-func newV1TopImage(imageID image.ID, img *image.Image, l layer.Layer, parent *v1DependencyImage) (*v1TopImage, error) {
|
|
| 92 |
- v1ID := imageID.Digest().Hex() |
|
| 93 |
- parentV1ID := "" |
|
| 94 |
- if parent != nil {
|
|
| 95 |
- parentV1ID = parent.V1ID() |
|
| 96 |
- } |
|
| 97 |
- |
|
| 98 |
- config, err := v1.MakeV1ConfigFromConfig(img, v1ID, parentV1ID, false) |
|
| 99 |
- if err != nil {
|
|
| 100 |
- return nil, err |
|
| 101 |
- } |
|
| 102 |
- |
|
| 103 |
- return &v1TopImage{
|
|
| 104 |
- v1ImageCommon: v1ImageCommon{
|
|
| 105 |
- v1ID: v1ID, |
|
| 106 |
- config: config, |
|
| 107 |
- layer: l, |
|
| 108 |
- }, |
|
| 109 |
- imageID: imageID, |
|
| 110 |
- }, nil |
|
| 111 |
-} |
|
| 112 |
- |
|
| 113 |
-// v1DependencyImage defines a dependency layer being pushed to a v1 registry. |
|
| 114 |
-type v1DependencyImage struct {
|
|
| 115 |
- v1ImageCommon |
|
| 116 |
-} |
|
| 117 |
- |
|
| 118 |
-func newV1DependencyImage(l layer.Layer, parent *v1DependencyImage) *v1DependencyImage {
|
|
| 119 |
- v1ID := digest.Digest(l.ChainID()).Hex() |
|
| 120 |
- |
|
| 121 |
- var config string |
|
| 122 |
- if parent != nil {
|
|
| 123 |
- config = fmt.Sprintf(`{"id":"%s","parent":"%s"}`, v1ID, parent.V1ID())
|
|
| 124 |
- } else {
|
|
| 125 |
- config = fmt.Sprintf(`{"id":"%s"}`, v1ID)
|
|
| 126 |
- } |
|
| 127 |
- return &v1DependencyImage{
|
|
| 128 |
- v1ImageCommon: v1ImageCommon{
|
|
| 129 |
- v1ID: v1ID, |
|
| 130 |
- config: []byte(config), |
|
| 131 |
- layer: l, |
|
| 132 |
- }, |
|
| 133 |
- } |
|
| 134 |
-} |
|
| 135 |
- |
|
| 136 |
-// Retrieve the all the images to be uploaded in the correct order |
|
| 137 |
-func (p *v1Pusher) getImageList() (imageList []v1Image, tagsByImage map[image.ID][]string, referencedLayers []PushLayer, err error) {
|
|
| 138 |
- tagsByImage = make(map[image.ID][]string) |
|
| 139 |
- |
|
| 140 |
- // Ignore digest references |
|
| 141 |
- if _, isCanonical := p.ref.(reference.Canonical); isCanonical {
|
|
| 142 |
- return |
|
| 143 |
- } |
|
| 144 |
- |
|
| 145 |
- tagged, isTagged := p.ref.(reference.NamedTagged) |
|
| 146 |
- if isTagged {
|
|
| 147 |
- // Push a specific tag |
|
| 148 |
- var imgID image.ID |
|
| 149 |
- var dgst digest.Digest |
|
| 150 |
- dgst, err = p.config.ReferenceStore.Get(p.ref) |
|
| 151 |
- if err != nil {
|
|
| 152 |
- return |
|
| 153 |
- } |
|
| 154 |
- imgID = image.IDFromDigest(dgst) |
|
| 155 |
- |
|
| 156 |
- imageList, err = p.imageListForTag(imgID, nil, &referencedLayers) |
|
| 157 |
- if err != nil {
|
|
| 158 |
- return |
|
| 159 |
- } |
|
| 160 |
- |
|
| 161 |
- tagsByImage[imgID] = []string{tagged.Tag()}
|
|
| 162 |
- |
|
| 163 |
- return |
|
| 164 |
- } |
|
| 165 |
- |
|
| 166 |
- imagesSeen := make(map[digest.Digest]struct{})
|
|
| 167 |
- dependenciesSeen := make(map[layer.ChainID]*v1DependencyImage) |
|
| 168 |
- |
|
| 169 |
- associations := p.config.ReferenceStore.ReferencesByName(p.ref) |
|
| 170 |
- for _, association := range associations {
|
|
| 171 |
- if tagged, isTagged = association.Ref.(reference.NamedTagged); !isTagged {
|
|
| 172 |
- // Ignore digest references. |
|
| 173 |
- continue |
|
| 174 |
- } |
|
| 175 |
- |
|
| 176 |
- imgID := image.IDFromDigest(association.ID) |
|
| 177 |
- tagsByImage[imgID] = append(tagsByImage[imgID], tagged.Tag()) |
|
| 178 |
- |
|
| 179 |
- if _, present := imagesSeen[association.ID]; present {
|
|
| 180 |
- // Skip generating image list for already-seen image |
|
| 181 |
- continue |
|
| 182 |
- } |
|
| 183 |
- imagesSeen[association.ID] = struct{}{}
|
|
| 184 |
- |
|
| 185 |
- imageListForThisTag, err := p.imageListForTag(imgID, dependenciesSeen, &referencedLayers) |
|
| 186 |
- if err != nil {
|
|
| 187 |
- return nil, nil, nil, err |
|
| 188 |
- } |
|
| 189 |
- |
|
| 190 |
- // append to main image list |
|
| 191 |
- imageList = append(imageList, imageListForThisTag...) |
|
| 192 |
- } |
|
| 193 |
- if len(imageList) == 0 {
|
|
| 194 |
- return nil, nil, nil, fmt.Errorf("No images found for the requested repository / tag")
|
|
| 195 |
- } |
|
| 196 |
- logrus.Debugf("Image list: %v", imageList)
|
|
| 197 |
- logrus.Debugf("Tags by image: %v", tagsByImage)
|
|
| 198 |
- |
|
| 199 |
- return |
|
| 200 |
-} |
|
| 201 |
- |
|
| 202 |
-func (p *v1Pusher) imageListForTag(imgID image.ID, dependenciesSeen map[layer.ChainID]*v1DependencyImage, referencedLayers *[]PushLayer) (imageListForThisTag []v1Image, err error) {
|
|
| 203 |
- ics, ok := p.config.ImageStore.(*imageConfigStore) |
|
| 204 |
- if !ok {
|
|
| 205 |
- return nil, fmt.Errorf("only image store images supported for v1 push")
|
|
| 206 |
- } |
|
| 207 |
- img, err := ics.Store.Get(imgID) |
|
| 208 |
- if err != nil {
|
|
| 209 |
- return nil, err |
|
| 210 |
- } |
|
| 211 |
- |
|
| 212 |
- topLayerID := img.RootFS.ChainID() |
|
| 213 |
- |
|
| 214 |
- if !system.IsOSSupported(img.OperatingSystem()) {
|
|
| 215 |
- return nil, system.ErrNotSupportedOperatingSystem |
|
| 216 |
- } |
|
| 217 |
- pl, err := p.config.LayerStores[img.OperatingSystem()].Get(topLayerID) |
|
| 218 |
- *referencedLayers = append(*referencedLayers, pl) |
|
| 219 |
- if err != nil {
|
|
| 220 |
- return nil, fmt.Errorf("failed to get top layer from image: %v", err)
|
|
| 221 |
- } |
|
| 222 |
- |
|
| 223 |
- // V1 push is deprecated, only support existing layerstore layers |
|
| 224 |
- lsl, ok := pl.(*storeLayer) |
|
| 225 |
- if !ok {
|
|
| 226 |
- return nil, fmt.Errorf("only layer store layers supported for v1 push")
|
|
| 227 |
- } |
|
| 228 |
- l := lsl.Layer |
|
| 229 |
- |
|
| 230 |
- dependencyImages, parent := generateDependencyImages(l.Parent(), dependenciesSeen) |
|
| 231 |
- |
|
| 232 |
- topImage, err := newV1TopImage(imgID, img, l, parent) |
|
| 233 |
- if err != nil {
|
|
| 234 |
- return nil, err |
|
| 235 |
- } |
|
| 236 |
- |
|
| 237 |
- imageListForThisTag = append(dependencyImages, topImage) |
|
| 238 |
- |
|
| 239 |
- return |
|
| 240 |
-} |
|
| 241 |
- |
|
| 242 |
-func generateDependencyImages(l layer.Layer, dependenciesSeen map[layer.ChainID]*v1DependencyImage) (imageListForThisTag []v1Image, parent *v1DependencyImage) {
|
|
| 243 |
- if l == nil {
|
|
| 244 |
- return nil, nil |
|
| 245 |
- } |
|
| 246 |
- |
|
| 247 |
- imageListForThisTag, parent = generateDependencyImages(l.Parent(), dependenciesSeen) |
|
| 248 |
- |
|
| 249 |
- if dependenciesSeen != nil {
|
|
| 250 |
- if dependencyImage, present := dependenciesSeen[l.ChainID()]; present {
|
|
| 251 |
- // This layer is already on the list, we can ignore it |
|
| 252 |
- // and all its parents. |
|
| 253 |
- return imageListForThisTag, dependencyImage |
|
| 254 |
- } |
|
| 255 |
- } |
|
| 256 |
- |
|
| 257 |
- dependencyImage := newV1DependencyImage(l, parent) |
|
| 258 |
- imageListForThisTag = append(imageListForThisTag, dependencyImage) |
|
| 259 |
- |
|
| 260 |
- if dependenciesSeen != nil {
|
|
| 261 |
- dependenciesSeen[l.ChainID()] = dependencyImage |
|
| 262 |
- } |
|
| 263 |
- |
|
| 264 |
- return imageListForThisTag, dependencyImage |
|
| 265 |
-} |
|
| 266 |
- |
|
| 267 |
-// createImageIndex returns an index of an image's layer IDs and tags. |
|
| 268 |
-func createImageIndex(images []v1Image, tags map[image.ID][]string) []*registry.ImgData {
|
|
| 269 |
- var imageIndex []*registry.ImgData |
|
| 270 |
- for _, img := range images {
|
|
| 271 |
- v1ID := img.V1ID() |
|
| 272 |
- |
|
| 273 |
- if topImage, isTopImage := img.(*v1TopImage); isTopImage {
|
|
| 274 |
- if tags, hasTags := tags[topImage.imageID]; hasTags {
|
|
| 275 |
- // If an image has tags you must add an entry in the image index |
|
| 276 |
- // for each tag |
|
| 277 |
- for _, tag := range tags {
|
|
| 278 |
- imageIndex = append(imageIndex, ®istry.ImgData{
|
|
| 279 |
- ID: v1ID, |
|
| 280 |
- Tag: tag, |
|
| 281 |
- }) |
|
| 282 |
- } |
|
| 283 |
- continue |
|
| 284 |
- } |
|
| 285 |
- } |
|
| 286 |
- |
|
| 287 |
- // If the image does not have a tag it still needs to be sent to the |
|
| 288 |
- // registry with an empty tag so that it is associated with the repository |
|
| 289 |
- imageIndex = append(imageIndex, ®istry.ImgData{
|
|
| 290 |
- ID: v1ID, |
|
| 291 |
- Tag: "", |
|
| 292 |
- }) |
|
| 293 |
- } |
|
| 294 |
- return imageIndex |
|
| 295 |
-} |
|
| 296 |
- |
|
| 297 |
-// lookupImageOnEndpoint checks the specified endpoint to see if an image exists |
|
| 298 |
-// and if it is absent then it sends the image id to the channel to be pushed. |
|
| 299 |
-func (p *v1Pusher) lookupImageOnEndpoint(wg *sync.WaitGroup, endpoint string, images chan v1Image, imagesToPush chan string) {
|
|
| 300 |
- defer wg.Done() |
|
| 301 |
- for image := range images {
|
|
| 302 |
- v1ID := image.V1ID() |
|
| 303 |
- truncID := stringid.TruncateID(image.Layer().DiffID().String()) |
|
| 304 |
- if err := p.session.LookupRemoteImage(v1ID, endpoint); err != nil {
|
|
| 305 |
- logrus.Errorf("Error in LookupRemoteImage: %s", err)
|
|
| 306 |
- imagesToPush <- v1ID |
|
| 307 |
- progress.Update(p.config.ProgressOutput, truncID, "Waiting") |
|
| 308 |
- } else {
|
|
| 309 |
- progress.Update(p.config.ProgressOutput, truncID, "Already exists") |
|
| 310 |
- } |
|
| 311 |
- } |
|
| 312 |
-} |
|
| 313 |
- |
|
| 314 |
-func (p *v1Pusher) pushImageToEndpoint(ctx context.Context, endpoint string, imageList []v1Image, tags map[image.ID][]string, repo *registry.RepositoryData) error {
|
|
| 315 |
- workerCount := len(imageList) |
|
| 316 |
- // start a maximum of 5 workers to check if images exist on the specified endpoint. |
|
| 317 |
- if workerCount > 5 {
|
|
| 318 |
- workerCount = 5 |
|
| 319 |
- } |
|
| 320 |
- var ( |
|
| 321 |
- wg = &sync.WaitGroup{}
|
|
| 322 |
- imageData = make(chan v1Image, workerCount*2) |
|
| 323 |
- imagesToPush = make(chan string, workerCount*2) |
|
| 324 |
- pushes = make(chan map[string]struct{}, 1)
|
|
| 325 |
- ) |
|
| 326 |
- for i := 0; i < workerCount; i++ {
|
|
| 327 |
- wg.Add(1) |
|
| 328 |
- go p.lookupImageOnEndpoint(wg, endpoint, imageData, imagesToPush) |
|
| 329 |
- } |
|
| 330 |
- // start a go routine that consumes the images to push |
|
| 331 |
- go func() {
|
|
| 332 |
- shouldPush := make(map[string]struct{})
|
|
| 333 |
- for id := range imagesToPush {
|
|
| 334 |
- shouldPush[id] = struct{}{}
|
|
| 335 |
- } |
|
| 336 |
- pushes <- shouldPush |
|
| 337 |
- }() |
|
| 338 |
- for _, v1Image := range imageList {
|
|
| 339 |
- imageData <- v1Image |
|
| 340 |
- } |
|
| 341 |
- // close the channel to notify the workers that there will be no more images to check. |
|
| 342 |
- close(imageData) |
|
| 343 |
- wg.Wait() |
|
| 344 |
- close(imagesToPush) |
|
| 345 |
- // wait for all the images that require pushes to be collected into a consumable map. |
|
| 346 |
- shouldPush := <-pushes |
|
| 347 |
- // finish by pushing any images and tags to the endpoint. The order that the images are pushed |
|
| 348 |
- // is very important that is why we are still iterating over the ordered list of imageIDs. |
|
| 349 |
- for _, img := range imageList {
|
|
| 350 |
- v1ID := img.V1ID() |
|
| 351 |
- if _, push := shouldPush[v1ID]; push {
|
|
| 352 |
- if _, err := p.pushImage(ctx, img, endpoint); err != nil {
|
|
| 353 |
- // FIXME: Continue on error? |
|
| 354 |
- return err |
|
| 355 |
- } |
|
| 356 |
- } |
|
| 357 |
- if topImage, isTopImage := img.(*v1TopImage); isTopImage {
|
|
| 358 |
- for _, tag := range tags[topImage.imageID] {
|
|
| 359 |
- progress.Messagef(p.config.ProgressOutput, "", "Pushing tag for rev [%s] on {%s}", stringid.TruncateID(v1ID), endpoint+"repositories/"+reference.Path(p.repoInfo.Name)+"/tags/"+tag)
|
|
| 360 |
- if err := p.session.PushRegistryTag(p.repoInfo.Name, v1ID, tag, endpoint); err != nil {
|
|
| 361 |
- return err |
|
| 362 |
- } |
|
| 363 |
- } |
|
| 364 |
- } |
|
| 365 |
- } |
|
| 366 |
- return nil |
|
| 367 |
-} |
|
| 368 |
- |
|
| 369 |
-// pushRepository pushes layers that do not already exist on the registry. |
|
| 370 |
-func (p *v1Pusher) pushRepository(ctx context.Context) error {
|
|
| 371 |
- imgList, tags, referencedLayers, err := p.getImageList() |
|
| 372 |
- defer func() {
|
|
| 373 |
- for _, l := range referencedLayers {
|
|
| 374 |
- l.Release() |
|
| 375 |
- } |
|
| 376 |
- }() |
|
| 377 |
- if err != nil {
|
|
| 378 |
- return err |
|
| 379 |
- } |
|
| 380 |
- |
|
| 381 |
- imageIndex := createImageIndex(imgList, tags) |
|
| 382 |
- for _, data := range imageIndex {
|
|
| 383 |
- logrus.Debugf("Pushing ID: %s with Tag: %s", data.ID, data.Tag)
|
|
| 384 |
- } |
|
| 385 |
- |
|
| 386 |
- // Register all the images in a repository with the registry |
|
| 387 |
- // If an image is not in this list it will not be associated with the repository |
|
| 388 |
- repoData, err := p.session.PushImageJSONIndex(p.repoInfo.Name, imageIndex, false, nil) |
|
| 389 |
- if err != nil {
|
|
| 390 |
- return err |
|
| 391 |
- } |
|
| 392 |
- // push the repository to each of the endpoints only if it does not exist. |
|
| 393 |
- for _, endpoint := range repoData.Endpoints {
|
|
| 394 |
- if err := p.pushImageToEndpoint(ctx, endpoint, imgList, tags, repoData); err != nil {
|
|
| 395 |
- return err |
|
| 396 |
- } |
|
| 397 |
- } |
|
| 398 |
- _, err = p.session.PushImageJSONIndex(p.repoInfo.Name, imageIndex, true, repoData.Endpoints) |
|
| 399 |
- return err |
|
| 400 |
-} |
|
| 401 |
- |
|
| 402 |
-func (p *v1Pusher) pushImage(ctx context.Context, v1Image v1Image, ep string) (checksum string, err error) {
|
|
| 403 |
- l := v1Image.Layer() |
|
| 404 |
- v1ID := v1Image.V1ID() |
|
| 405 |
- truncID := stringid.TruncateID(l.DiffID().String()) |
|
| 406 |
- |
|
| 407 |
- jsonRaw := v1Image.Config() |
|
| 408 |
- progress.Update(p.config.ProgressOutput, truncID, "Pushing") |
|
| 409 |
- |
|
| 410 |
- // General rule is to use ID for graph accesses and compatibilityID for |
|
| 411 |
- // calls to session.registry() |
|
| 412 |
- imgData := ®istry.ImgData{
|
|
| 413 |
- ID: v1ID, |
|
| 414 |
- } |
|
| 415 |
- |
|
| 416 |
- // Send the json |
|
| 417 |
- if err := p.session.PushImageJSONRegistry(imgData, jsonRaw, ep); err != nil {
|
|
| 418 |
- if err == registry.ErrAlreadyExists {
|
|
| 419 |
- progress.Update(p.config.ProgressOutput, truncID, "Image already pushed, skipping") |
|
| 420 |
- return "", nil |
|
| 421 |
- } |
|
| 422 |
- return "", err |
|
| 423 |
- } |
|
| 424 |
- |
|
| 425 |
- arch, err := l.TarStream() |
|
| 426 |
- if err != nil {
|
|
| 427 |
- return "", err |
|
| 428 |
- } |
|
| 429 |
- defer arch.Close() |
|
| 430 |
- |
|
| 431 |
- // don't care if this fails; best effort |
|
| 432 |
- size, _ := l.DiffSize() |
|
| 433 |
- |
|
| 434 |
- // Send the layer |
|
| 435 |
- logrus.Debugf("rendered layer for %s of [%d] size", v1ID, size)
|
|
| 436 |
- |
|
| 437 |
- reader := progress.NewProgressReader(ioutils.NewCancelReadCloser(ctx, arch), p.config.ProgressOutput, size, truncID, "Pushing") |
|
| 438 |
- defer reader.Close() |
|
| 439 |
- |
|
| 440 |
- checksum, checksumPayload, err := p.session.PushImageLayerRegistry(v1ID, reader, ep, jsonRaw) |
|
| 441 |
- if err != nil {
|
|
| 442 |
- return "", err |
|
| 443 |
- } |
|
| 444 |
- imgData.Checksum = checksum |
|
| 445 |
- imgData.ChecksumPayload = checksumPayload |
|
| 446 |
- // Send the checksum |
|
| 447 |
- if err := p.session.PushImageChecksumRegistry(imgData, ep); err != nil {
|
|
| 448 |
- return "", err |
|
| 449 |
- } |
|
| 450 |
- |
|
| 451 |
- if err := p.v1IDService.Set(v1ID, p.repoInfo.Index.Name, l.DiffID()); err != nil {
|
|
| 452 |
- logrus.Warnf("Could not set v1 ID mapping: %v", err)
|
|
| 453 |
- } |
|
| 454 |
- |
|
| 455 |
- progress.Update(p.config.ProgressOutput, truncID, "Image successfully pushed") |
|
| 456 |
- return imgData.Checksum, nil |
|
| 457 |
-} |
| ... | ... |
@@ -92,7 +92,7 @@ func CreateInRegistry(ctx context.Context, repo string, auth *types.AuthConfig, |
| 92 | 92 |
return nil, nil |
| 93 | 93 |
} |
| 94 | 94 |
|
| 95 |
- regService, err := registry.NewService(registry.ServiceOptions{V2Only: true})
|
|
| 95 |
+ regService, err := registry.NewService(registry.ServiceOptions{})
|
|
| 96 | 96 |
if err != nil {
|
| 97 | 97 |
return err |
| 98 | 98 |
} |
| ... | ... |
@@ -19,16 +19,11 @@ type ServiceOptions struct {
|
| 19 | 19 |
AllowNondistributableArtifacts []string `json:"allow-nondistributable-artifacts,omitempty"` |
| 20 | 20 |
Mirrors []string `json:"registry-mirrors,omitempty"` |
| 21 | 21 |
InsecureRegistries []string `json:"insecure-registries,omitempty"` |
| 22 |
- |
|
| 23 |
- // V2Only controls access to legacy registries. If it is set to true via the |
|
| 24 |
- // command line flag the daemon will not attempt to contact v1 legacy registries |
|
| 25 |
- V2Only bool `json:"disable-legacy-registry,omitempty"` |
|
| 26 | 22 |
} |
| 27 | 23 |
|
| 28 | 24 |
// serviceConfig holds daemon configuration for the registry service. |
| 29 | 25 |
type serviceConfig struct {
|
| 30 | 26 |
registrytypes.ServiceConfig |
| 31 |
- V2Only bool |
|
| 32 | 27 |
} |
| 33 | 28 |
|
| 34 | 29 |
var ( |
| ... | ... |
@@ -76,7 +71,6 @@ func newServiceConfig(options ServiceOptions) (*serviceConfig, error) {
|
| 76 | 76 |
// Hack: Bypass setting the mirrors to IndexConfigs since they are going away |
| 77 | 77 |
// and Mirrors are only for the official registry anyways. |
| 78 | 78 |
}, |
| 79 |
- V2Only: options.V2Only, |
|
| 80 | 79 |
} |
| 81 | 80 |
if err := config.LoadAllowNondistributableArtifacts(options.AllowNondistributableArtifacts); err != nil {
|
| 82 | 81 |
return nil, err |
| ... | ... |
@@ -309,20 +309,5 @@ func (s *DefaultService) LookupPushEndpoints(hostname string) (endpoints []APIEn |
| 309 | 309 |
} |
| 310 | 310 |
|
| 311 | 311 |
func (s *DefaultService) lookupEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
| 312 |
- endpoints, err = s.lookupV2Endpoints(hostname) |
|
| 313 |
- if err != nil {
|
|
| 314 |
- return nil, err |
|
| 315 |
- } |
|
| 316 |
- |
|
| 317 |
- if s.config.V2Only {
|
|
| 318 |
- return endpoints, nil |
|
| 319 |
- } |
|
| 320 |
- |
|
| 321 |
- legacyEndpoints, err := s.lookupV1Endpoints(hostname) |
|
| 322 |
- if err != nil {
|
|
| 323 |
- return nil, err |
|
| 324 |
- } |
|
| 325 |
- endpoints = append(endpoints, legacyEndpoints...) |
|
| 326 |
- |
|
| 327 |
- return endpoints, nil |
|
| 312 |
+ return s.lookupV2Endpoints(hostname) |
|
| 328 | 313 |
} |
| 329 | 314 |
deleted file mode 100644 |
| ... | ... |
@@ -1,40 +0,0 @@ |
| 1 |
-package registry // import "github.com/docker/docker/registry" |
|
| 2 |
- |
|
| 3 |
-import "net/url" |
|
| 4 |
- |
|
| 5 |
-func (s *DefaultService) lookupV1Endpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
|
| 6 |
- if hostname == DefaultNamespace || hostname == DefaultV2Registry.Host || hostname == IndexHostname {
|
|
| 7 |
- return []APIEndpoint{}, nil
|
|
| 8 |
- } |
|
| 9 |
- |
|
| 10 |
- tlsConfig, err := s.tlsConfig(hostname) |
|
| 11 |
- if err != nil {
|
|
| 12 |
- return nil, err |
|
| 13 |
- } |
|
| 14 |
- |
|
| 15 |
- endpoints = []APIEndpoint{
|
|
| 16 |
- {
|
|
| 17 |
- URL: &url.URL{
|
|
| 18 |
- Scheme: "https", |
|
| 19 |
- Host: hostname, |
|
| 20 |
- }, |
|
| 21 |
- Version: APIVersion1, |
|
| 22 |
- TrimHostname: true, |
|
| 23 |
- TLSConfig: tlsConfig, |
|
| 24 |
- }, |
|
| 25 |
- } |
|
| 26 |
- |
|
| 27 |
- if tlsConfig.InsecureSkipVerify {
|
|
| 28 |
- endpoints = append(endpoints, APIEndpoint{ // or this
|
|
| 29 |
- URL: &url.URL{
|
|
| 30 |
- Scheme: "http", |
|
| 31 |
- Host: hostname, |
|
| 32 |
- }, |
|
| 33 |
- Version: APIVersion1, |
|
| 34 |
- TrimHostname: true, |
|
| 35 |
- // used to check if supposed to be secure via InsecureSkipVerify |
|
| 36 |
- TLSConfig: tlsConfig, |
|
| 37 |
- }) |
|
| 38 |
- } |
|
| 39 |
- return endpoints, nil |
|
| 40 |
-} |
| 41 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,32 +0,0 @@ |
| 1 |
-package registry // import "github.com/docker/docker/registry" |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "os" |
|
| 5 |
- "testing" |
|
| 6 |
- |
|
| 7 |
- "gotest.tools/skip" |
|
| 8 |
-) |
|
| 9 |
- |
|
| 10 |
-func TestLookupV1Endpoints(t *testing.T) {
|
|
| 11 |
- skip.If(t, os.Getuid() != 0, "skipping test that requires root") |
|
| 12 |
- s, err := NewService(ServiceOptions{})
|
|
| 13 |
- if err != nil {
|
|
| 14 |
- t.Fatal(err) |
|
| 15 |
- } |
|
| 16 |
- |
|
| 17 |
- cases := []struct {
|
|
| 18 |
- hostname string |
|
| 19 |
- expectedLen int |
|
| 20 |
- }{
|
|
| 21 |
- {"example.com", 1},
|
|
| 22 |
- {DefaultNamespace, 0},
|
|
| 23 |
- {DefaultV2Registry.Host, 0},
|
|
| 24 |
- {IndexHostname, 0},
|
|
| 25 |
- } |
|
| 26 |
- |
|
| 27 |
- for _, c := range cases {
|
|
| 28 |
- if ret, err := s.lookupV1Endpoints(c.hostname); err != nil || len(ret) != c.expectedLen {
|
|
| 29 |
- t.Errorf("lookupV1Endpoints(`"+c.hostname+"`) returned %+v and %+v", ret, err)
|
|
| 30 |
- } |
|
| 31 |
- } |
|
| 32 |
-} |