Move temporary download file to download descriptor scope
This will allow it to be reused between download attempts in a subsequent commit. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
fa860c86ff
commit
f425529e7e
5 changed files with 57 additions and 25 deletions
|
@ -2,7 +2,6 @@ package distribution
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api"
|
||||
|
@ -187,16 +186,3 @@ func validateRepoName(name string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// tmpFileClose creates a closer function for a temporary file that closes the file
|
||||
// and also deletes it.
|
||||
func tmpFileCloser(tmpFile *os.File) func() error {
|
||||
return func() error {
|
||||
tmpFile.Close()
|
||||
if err := os.RemoveAll(tmpFile.Name()); err != nil {
|
||||
logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -279,6 +280,7 @@ type v1LayerDescriptor struct {
|
|||
layersDownloaded *bool
|
||||
layerSize int64
|
||||
session *registry.Session
|
||||
tmpFile *os.File
|
||||
}
|
||||
|
||||
func (ld *v1LayerDescriptor) Key() string {
|
||||
|
@ -308,7 +310,7 @@ func (ld *v1LayerDescriptor) Download(ctx context.Context, progressOutput progre
|
|||
}
|
||||
*ld.layersDownloaded = true
|
||||
|
||||
tmpFile, err := ioutil.TempFile("", "GetImageBlob")
|
||||
ld.tmpFile, err = ioutil.TempFile("", "GetImageBlob")
|
||||
if err != nil {
|
||||
layerReader.Close()
|
||||
return nil, 0, err
|
||||
|
@ -317,17 +319,28 @@ func (ld *v1LayerDescriptor) Download(ctx context.Context, progressOutput progre
|
|||
reader := progress.NewProgressReader(ioutils.NewCancelReadCloser(ctx, layerReader), progressOutput, ld.layerSize, ld.ID(), "Downloading")
|
||||
defer reader.Close()
|
||||
|
||||
_, err = io.Copy(tmpFile, reader)
|
||||
_, err = io.Copy(ld.tmpFile, reader)
|
||||
if err != nil {
|
||||
ld.Close()
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
progress.Update(progressOutput, ld.ID(), "Download complete")
|
||||
|
||||
logrus.Debugf("Downloaded %s to tempfile %s", ld.ID(), tmpFile.Name())
|
||||
logrus.Debugf("Downloaded %s to tempfile %s", ld.ID(), ld.tmpFile.Name())
|
||||
|
||||
tmpFile.Seek(0, 0)
|
||||
return ioutils.NewReadCloserWrapper(tmpFile, tmpFileCloser(tmpFile)), ld.layerSize, nil
|
||||
ld.tmpFile.Seek(0, 0)
|
||||
return ld.tmpFile, ld.layerSize, nil
|
||||
}
|
||||
|
||||
func (ld *v1LayerDescriptor) Close() {
|
||||
if ld.tmpFile != nil {
|
||||
ld.tmpFile.Close()
|
||||
if err := os.RemoveAll(ld.tmpFile.Name()); err != nil {
|
||||
logrus.Errorf("Failed to remove temp file: %s", ld.tmpFile.Name())
|
||||
}
|
||||
ld.tmpFile = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (ld *v1LayerDescriptor) Registered(diffID layer.DiffID) {
|
||||
|
|
|
@ -114,6 +114,7 @@ type v2LayerDescriptor struct {
|
|||
repoInfo *registry.RepositoryInfo
|
||||
repo distribution.Repository
|
||||
V2MetadataService *metadata.V2MetadataService
|
||||
tmpFile *os.File
|
||||
}
|
||||
|
||||
func (ld *v2LayerDescriptor) Key() string {
|
||||
|
@ -131,6 +132,18 @@ func (ld *v2LayerDescriptor) DiffID() (layer.DiffID, error) {
|
|||
func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progress.Output) (io.ReadCloser, int64, error) {
|
||||
logrus.Debugf("pulling blob %q", ld.digest)
|
||||
|
||||
var err error
|
||||
|
||||
if ld.tmpFile == nil {
|
||||
ld.tmpFile, err = createDownloadFile()
|
||||
} else {
|
||||
_, err = ld.tmpFile.Seek(0, os.SEEK_SET)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, 0, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
||||
tmpFile := ld.tmpFile
|
||||
blobs := ld.repo.Blobs(ctx)
|
||||
|
||||
layerDownload, err := blobs.Open(ctx, ld.digest)
|
||||
|
@ -164,17 +177,13 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre
|
|||
return nil, 0, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
||||
tmpFile, err := ioutil.TempFile("", "GetImageBlob")
|
||||
if err != nil {
|
||||
return nil, 0, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
||||
_, err = io.Copy(tmpFile, io.TeeReader(reader, verifier))
|
||||
if err != nil {
|
||||
tmpFile.Close()
|
||||
if err := os.Remove(tmpFile.Name()); err != nil {
|
||||
logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
|
||||
}
|
||||
ld.tmpFile = nil
|
||||
return nil, 0, retryOnError(err)
|
||||
}
|
||||
|
||||
|
@ -188,6 +197,7 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre
|
|||
if err := os.Remove(tmpFile.Name()); err != nil {
|
||||
logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
|
||||
}
|
||||
ld.tmpFile = nil
|
||||
|
||||
return nil, 0, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
|
@ -202,9 +212,19 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre
|
|||
if err := os.Remove(tmpFile.Name()); err != nil {
|
||||
logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
|
||||
}
|
||||
ld.tmpFile = nil
|
||||
return nil, 0, xfer.DoNotRetry{Err: err}
|
||||
}
|
||||
return ioutils.NewReadCloserWrapper(tmpFile, tmpFileCloser(tmpFile)), size, nil
|
||||
return tmpFile, size, nil
|
||||
}
|
||||
|
||||
func (ld *v2LayerDescriptor) Close() {
|
||||
if ld.tmpFile != nil {
|
||||
ld.tmpFile.Close()
|
||||
if err := os.RemoveAll(ld.tmpFile.Name()); err != nil {
|
||||
logrus.Errorf("Failed to remove temp file: %s", ld.tmpFile.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ld *v2LayerDescriptor) Registered(diffID layer.DiffID) {
|
||||
|
@ -711,3 +731,7 @@ func fixManifestLayers(m *schema1.Manifest) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createDownloadFile() (*os.File, error) {
|
||||
return ioutil.TempFile("", "GetImageBlob")
|
||||
}
|
||||
|
|
|
@ -59,6 +59,10 @@ type DownloadDescriptor interface {
|
|||
DiffID() (layer.DiffID, error)
|
||||
// Download is called to perform the download.
|
||||
Download(ctx context.Context, progressOutput progress.Output) (io.ReadCloser, int64, error)
|
||||
// Close is called when the download manager is finished with this
|
||||
// descriptor and will not call Download again or read from the reader
|
||||
// that Download returned.
|
||||
Close()
|
||||
}
|
||||
|
||||
// DownloadDescriptorWithRegistered is a DownloadDescriptor that has an
|
||||
|
@ -229,6 +233,8 @@ func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor,
|
|||
retries int
|
||||
)
|
||||
|
||||
defer descriptor.Close()
|
||||
|
||||
for {
|
||||
downloadReader, size, err = descriptor.Download(d.Transfer.Context(), progressOutput)
|
||||
if err == nil {
|
||||
|
|
|
@ -199,6 +199,9 @@ func (d *mockDownloadDescriptor) Download(ctx context.Context, progressOutput pr
|
|||
return d.mockTarStream(), 0, nil
|
||||
}
|
||||
|
||||
func (d *mockDownloadDescriptor) Close() {
|
||||
}
|
||||
|
||||
func downloadDescriptors(currentDownloads *int32) []DownloadDescriptor {
|
||||
return []DownloadDescriptor{
|
||||
&mockDownloadDescriptor{
|
||||
|
|
Loading…
Add table
Reference in a new issue