mountBlob tries to mount blob srcDigest from srcRepo to the current destination.
(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest, extraScope *authScope)
| 262 | |
| 263 | // mountBlob tries to mount blob srcDigest from srcRepo to the current destination. |
| 264 | func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest, extraScope *authScope) error { |
| 265 | u := url.URL{ |
| 266 | Path: fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref)), |
| 267 | RawQuery: url.Values{ |
| 268 | "mount": {srcDigest.String()}, |
| 269 | "from": {reference.Path(srcRepo)}, |
| 270 | }.Encode(), |
| 271 | } |
| 272 | logrus.Debugf("Trying to mount %s", u.Redacted()) |
| 273 | res, err := d.c.makeRequest(ctx, http.MethodPost, u.String(), nil, nil, v2Auth, extraScope) |
| 274 | if err != nil { |
| 275 | return err |
| 276 | } |
| 277 | defer res.Body.Close() |
| 278 | switch res.StatusCode { |
| 279 | case http.StatusCreated: |
| 280 | logrus.Debugf("... mount OK") |
| 281 | return nil |
| 282 | case http.StatusAccepted: |
| 283 | // Oops, the mount was ignored - either the registry does not support that yet, or the blob does not exist; the registry has started an ordinary upload process. |
| 284 | // Abort, and let the ultimate caller do an upload when its ready, instead. |
| 285 | // NOTE: This does not really work in docker/distribution servers, which incorrectly require the "delete" action in the token's scope, and is thus entirely untested. |
| 286 | uploadLocation, err := res.Location() |
| 287 | if err != nil { |
| 288 | return fmt.Errorf("determining upload URL after a mount attempt: %w", err) |
| 289 | } |
| 290 | logrus.Debugf("... started an upload instead of mounting, trying to cancel at %s", uploadLocation.Redacted()) |
| 291 | res2, err := d.c.makeRequestToResolvedURL(ctx, http.MethodDelete, uploadLocation, nil, nil, -1, v2Auth, extraScope) |
| 292 | if err != nil { |
| 293 | logrus.Debugf("Error trying to cancel an inadvertent upload: %s", err) |
| 294 | } else { |
| 295 | defer res2.Body.Close() |
| 296 | if res2.StatusCode != http.StatusNoContent { |
| 297 | logrus.Debugf("Error trying to cancel an inadvertent upload, status %s", http.StatusText(res.StatusCode)) |
| 298 | } |
| 299 | } |
| 300 | // Anyway, if canceling the upload fails, ignore it and return the more important error: |
| 301 | return fmt.Errorf("Mounting %s from %s to %s started an upload instead", srcDigest, srcRepo.Name(), d.ref.ref.Name()) |
| 302 | default: |
| 303 | logrus.Debugf("Error mounting, response %#v", *res) |
| 304 | return fmt.Errorf("mounting %s from %s to %s: %w", srcDigest, srcRepo.Name(), d.ref.ref.Name(), registryHTTPResponseToError(res)) |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | // tryReusingExactBlob is a subset of TryReusingBlob which _only_ looks for exactly the specified |
| 309 | // blob in the current repository, with no cross-repo reuse or mounting; cache may be updated, it is not read. |
no test coverage detected