|
| @@ -157,12 +159,44 @@ func defaultImageSource(ctx context.Context, ref string) (v1.Image, error) { |
| 157 | | if err != nil { | 159 | | if err != nil { |
| 158 | | return nil, fmt.Errorf("failed to export image %s: %w", ref, err) | 160 | | return nil, fmt.Errorf("failed to export image %s: %w", ref, err) |
| 159 | | } | 161 | | } |
| 160 | - | defer rc.Close() | | | |
| 161 | | | 162 | | |
| 162 | - | img, err := tarball.Image(func() (io.ReadCloser, error) { | 163 | + | tmpFile, err := os.CreateTemp("", "gordon-push-*.tar") |
| 163 | - | return rc, nil | | | |
| 164 | - | }, &tag) | | | |
| 165 | | if err != nil { | 164 | | if err != nil { |
| | | 165 | + | if closeErr := rc.Close(); closeErr != nil { |
| | | 166 | + | return nil, fmt.Errorf("failed to create temp file for image export: %w (also failed to close image export stream: %v)", err, closeErr) |
| | | 167 | + | } |
| | | 168 | + | return nil, fmt.Errorf("failed to create temp file for image export: %w", err) |
| | | 169 | + | } |
| | | 170 | + | tmpPath := tmpFile.Name() |
| | | 171 | + | |
| | | 172 | + | if _, err := io.Copy(tmpFile, rc); err != nil { |
| | | 173 | + | if closeErr := rc.Close(); closeErr != nil { |
| | | 174 | + | _ = tmpFile.Close() |
| | | 175 | + | _ = os.Remove(tmpPath) |
| | | 176 | + | return nil, fmt.Errorf("failed to write image tar to temp file: %w (also failed to close image export stream: %v)", err, closeErr) |
| | | 177 | + | } |
| | | 178 | + | if closeErr := tmpFile.Close(); closeErr != nil { |
| | | 179 | + | _ = os.Remove(tmpPath) |
| | | 180 | + | return nil, fmt.Errorf("failed to write image tar to temp file: %w (also failed to close temp file: %v)", err, closeErr) |
| | | 181 | + | } |
| | | 182 | + | if removeErr := os.Remove(tmpPath); removeErr != nil { |
| | | 183 | + | return nil, fmt.Errorf("failed to write image tar to temp file: %w (also failed to remove temp file %s: %v)", err, tmpPath, removeErr) |
| | | 184 | + | } |
| | | 185 | + | return nil, fmt.Errorf("failed to write image tar to temp file: %w", err) |
| | | 186 | + | } |
| | | 187 | + | if err := rc.Close(); err != nil { |
| | | 188 | + | _ = tmpFile.Close() |
| | | 189 | + | _ = os.Remove(tmpPath) |
| | | 190 | + | return nil, fmt.Errorf("failed to close image export stream: %w", err) |
| | | 191 | + | } |
| | | 192 | + | if err := tmpFile.Close(); err != nil { |
| | | 193 | + | _ = os.Remove(tmpPath) |
| | | 194 | + | return nil, fmt.Errorf("failed to close temp file %s: %w", tmpPath, err) |
| | | 195 | + | } |
| | | 196 | + | |
| | | 197 | + | img, err := tarball.ImageFromPath(tmpPath, &tag) |
| | | 198 | + | if err != nil { |
| | | 199 | + | _ = os.Remove(tmpPath) |
| 166 | | return nil, fmt.Errorf("failed to parse image tar for %s: %w", ref, err) | 200 | | return nil, fmt.Errorf("failed to parse image tar for %s: %w", ref, err) |
| 167 | | } | 201 | | } |
| 168 | | return img, nil | 202 | | return img, nil |
|
| @@ -247,7 +281,8 @@ func (p *Pusher) uploadManifest(ctx context.Context, baseURL, repo, tag string, |
| 247 | | defer resp.Body.Close() | 281 | | defer resp.Body.Close() |
| 248 | | | 282 | | |
| 249 | | if resp.StatusCode != http.StatusCreated { | 283 | | if resp.StatusCode != http.StatusCreated { |
| 250 | - | return fmt.Errorf("manifest upload returned status %d", resp.StatusCode) | 284 | + | body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) |
| | | 285 | + | return fmt.Errorf("manifest upload returned status %d: %s", resp.StatusCode, string(body)) |
| 251 | | } | 286 | | } |
| 252 | | | 287 | | |
| 253 | | return nil | 288 | | return nil |
|
| @@ -279,7 +314,7 @@ func registryBaseURL(host string) string { |
| 279 | | return "https://" + host | 314 | | return "https://" + host |
| 280 | | } | 315 | | } |
| 281 | | | 316 | | |
| 282 | - | var errBlobMissing = fmt.Errorf("blob missing") | 317 | + | var errBlobMissing = errors.New("blob missing") |
| 283 | | | 318 | | |
| 284 | | func (p *Pusher) checkBlobExists(ctx context.Context, baseURL, repo, digest, auth string) error { | 319 | | func (p *Pusher) checkBlobExists(ctx context.Context, baseURL, repo, digest, auth string) error { |
| 285 | | req, err := http.NewRequestWithContext(ctx, http.MethodHead, fmt.Sprintf("%s/v2/%s/blobs/%s", baseURL, repo, digest), nil) | 320 | | req, err := http.NewRequestWithContext(ctx, http.MethodHead, fmt.Sprintf("%s/v2/%s/blobs/%s", baseURL, repo, digest), nil) |
|
| @@ -300,7 +335,8 @@ func (p *Pusher) checkBlobExists(ctx context.Context, baseURL, repo, digest, aut |
| 300 | | case http.StatusNotFound: | 335 | | case http.StatusNotFound: |
| 301 | | return errBlobMissing | 336 | | return errBlobMissing |
| 302 | | default: | 337 | | default: |
| 303 | - | return fmt.Errorf("blob existence check returned status %d", resp.StatusCode) | 338 | + | body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) |
| | | 339 | + | return fmt.Errorf("blob existence check returned status %d: %s", resp.StatusCode, string(body)) |
| 304 | | } | 340 | | } |
| 305 | | } | 341 | | } |
| 306 | | | 342 | | |
|
| @@ -318,7 +354,8 @@ func (p *Pusher) startBlobUpload(ctx context.Context, baseURL, repo, auth string |
| 318 | | defer resp.Body.Close() | 354 | | defer resp.Body.Close() |
| 319 | | | 355 | | |
| 320 | | if resp.StatusCode != http.StatusAccepted { | 356 | | if resp.StatusCode != http.StatusAccepted { |
| 321 | - | return "", fmt.Errorf("blob upload start returned status %d", resp.StatusCode) | 357 | + | body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) |
| | | 358 | + | return "", fmt.Errorf("blob upload start returned status %d: %s", resp.StatusCode, string(body)) |
| 322 | | } | 359 | | } |
| 323 | | | 360 | | |
| 324 | | location, err := resolveLocation(baseURL, resp.Header.Get("Location")) | 361 | | location, err := resolveLocation(baseURL, resp.Header.Get("Location")) |
|
| @@ -357,7 +394,7 @@ func (p *Pusher) uploadBlobChunks(ctx context.Context, uploadURL string, content |
| 357 | | } | 394 | | } |
| 358 | | | 395 | | |
| 359 | | func (p *Pusher) uploadBlobChunk(ctx context.Context, uploadURL string, chunk []byte, offset int64, auth string) (string, error) { | 396 | | func (p *Pusher) uploadBlobChunk(ctx context.Context, uploadURL string, chunk []byte, offset int64, auth string) (string, error) { |
| 360 | - | req, err := http.NewRequestWithContext(ctx, http.MethodPatch, uploadURL, io.NopCloser(io.LimitReader(bytesReader(chunk), int64(len(chunk))))) | 397 | + | req, err := http.NewRequestWithContext(ctx, http.MethodPatch, uploadURL, bytesReader(chunk)) |
| 361 | | if err != nil { | 398 | | if err != nil { |
| 362 | | return "", fmt.Errorf("failed to create blob chunk request: %w", err) | 399 | | return "", fmt.Errorf("failed to create blob chunk request: %w", err) |
| 363 | | } | 400 | | } |
|
| @@ -373,7 +410,8 @@ func (p *Pusher) uploadBlobChunk(ctx context.Context, uploadURL string, chunk [] |
| 373 | | defer resp.Body.Close() | 410 | | defer resp.Body.Close() |
| 374 | | | 411 | | |
| 375 | | if resp.StatusCode != http.StatusAccepted { | 412 | | if resp.StatusCode != http.StatusAccepted { |
| 376 | - | return "", fmt.Errorf("blob chunk upload returned status %d", resp.StatusCode) | 413 | + | body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) |
| | | 414 | + | return "", fmt.Errorf("blob chunk upload returned status %d: %s", resp.StatusCode, string(body)) |
| 377 | | } | 415 | | } |
| 378 | | | 416 | | |
| 379 | | nextURL, err := resolveLocation(uploadURL, resp.Header.Get("Location")) | 417 | | nextURL, err := resolveLocation(uploadURL, resp.Header.Get("Location")) |
|
| @@ -407,7 +445,8 @@ func (p *Pusher) finalizeBlobUpload(ctx context.Context, uploadURL, digest, auth |
| 407 | | defer resp.Body.Close() | 445 | | defer resp.Body.Close() |
| 408 | | | 446 | | |
| 409 | | if resp.StatusCode != http.StatusCreated { | 447 | | if resp.StatusCode != http.StatusCreated { |
| 410 | - | return fmt.Errorf("blob upload finalize returned status %d", resp.StatusCode) | 448 | + | body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) |
| | | 449 | + | return fmt.Errorf("blob upload finalize returned status %d: %s", resp.StatusCode, string(body)) |
| 411 | | } | 450 | | } |
| 412 | | | 451 | | |
| 413 | | return nil | 452 | | return nil |