94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
|
package client
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"io"
|
||
|
|
||
|
log "github.com/Sirupsen/logrus"
|
||
|
)
|
||
|
|
||
|
// Pull implements a client pull workflow for the image defined by the given
|
||
|
// name and tag pair, using the given ObjectStore for local manifest and layer
|
||
|
// storage
|
||
|
func Pull(c Client, objectStore ObjectStore, name, tag string) error {
|
||
|
manifest, err := c.GetImageManifest(name, tag)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
log.WithField("manifest", manifest).Info("Pulled manifest")
|
||
|
|
||
|
if len(manifest.FSLayers) != len(manifest.History) {
|
||
|
return fmt.Errorf("Length of history not equal to number of layers")
|
||
|
}
|
||
|
if len(manifest.FSLayers) == 0 {
|
||
|
return fmt.Errorf("Image has no layers")
|
||
|
}
|
||
|
|
||
|
for _, fsLayer := range manifest.FSLayers {
|
||
|
layer, err := objectStore.Layer(fsLayer.BlobSum)
|
||
|
if err != nil {
|
||
|
log.WithFields(log.Fields{
|
||
|
"error": err,
|
||
|
"layer": fsLayer,
|
||
|
}).Warn("Unable to write local layer")
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
writer, err := layer.Writer()
|
||
|
if err == ErrLayerAlreadyExists {
|
||
|
log.WithField("layer", fsLayer).Info("Layer already exists")
|
||
|
continue
|
||
|
}
|
||
|
if err == ErrLayerLocked {
|
||
|
log.WithField("layer", fsLayer).Info("Layer download in progress, waiting")
|
||
|
layer.Wait()
|
||
|
continue
|
||
|
}
|
||
|
if err != nil {
|
||
|
log.WithFields(log.Fields{
|
||
|
"error": err,
|
||
|
"layer": fsLayer,
|
||
|
}).Warn("Unable to write local layer")
|
||
|
return err
|
||
|
}
|
||
|
defer writer.Close()
|
||
|
|
||
|
layerReader, length, err := c.GetImageLayer(name, fsLayer.BlobSum, 0)
|
||
|
if err != nil {
|
||
|
log.WithFields(log.Fields{
|
||
|
"error": err,
|
||
|
"layer": fsLayer,
|
||
|
}).Warn("Unable to download layer")
|
||
|
return err
|
||
|
}
|
||
|
defer layerReader.Close()
|
||
|
|
||
|
copied, err := io.Copy(writer, layerReader)
|
||
|
if err != nil {
|
||
|
log.WithFields(log.Fields{
|
||
|
"error": err,
|
||
|
"layer": fsLayer,
|
||
|
}).Warn("Unable to download layer")
|
||
|
return err
|
||
|
}
|
||
|
if copied != int64(length) {
|
||
|
log.WithFields(log.Fields{
|
||
|
"expected": length,
|
||
|
"written": copied,
|
||
|
"layer": fsLayer,
|
||
|
}).Warn("Wrote incorrect number of bytes for layer")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err = objectStore.WriteManifest(name, tag, manifest)
|
||
|
if err != nil {
|
||
|
log.WithFields(log.Fields{
|
||
|
"error": err,
|
||
|
"manifest": manifest,
|
||
|
}).Warn("Unable to write image manifest")
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|