luet/vendor/github.com/mudler/docker-companion/api/download.go
Ettore Di Giacinto 420186b7db
Switch to go mod
2019-11-10 18:05:28 +01:00

156 lines
3.1 KiB
Go

package api
import (
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"github.com/heroku/docker-registry-client/registry"
jww "github.com/spf13/jwalterweatherman"
)
const defaultRegistryBase = "https://registry-1.docker.io"
type DownloadOpts struct {
RegistryBase string
KeepLayers bool
UnpackMode string
}
func DownloadAndUnpackImage(sourceImage, output string, opts *DownloadOpts) error {
if opts.RegistryBase == "" {
opts.RegistryBase = defaultRegistryBase
}
var TempDir = os.Getenv("TEMP_LAYER_FOLDER")
if TempDir == "" {
TempDir = "layers"
}
err := os.MkdirAll(TempDir, os.ModePerm)
if err != nil {
return err
}
if opts.KeepLayers == false {
defer os.RemoveAll(TempDir)
}
if sourceImage != "" && strings.Contains(sourceImage, ":") {
parts := strings.Split(sourceImage, ":")
if parts[0] == "" || parts[1] == "" {
return fmt.Errorf("Bad usage. Image should be in this format: foo/my-image:latest")
}
}
tagPart := "latest"
repoPart := sourceImage
parts := strings.Split(sourceImage, ":")
if len(parts) > 1 {
repoPart = parts[0]
tagPart = parts[1]
}
jww.INFO.Println("Unpacking", repoPart, "tag", tagPart, "in", output)
os.MkdirAll(output, os.ModePerm)
username := "" // anonymous
password := "" // anonymous
hub, err := registry.New(opts.RegistryBase, username, password)
if err != nil {
jww.ERROR.Fatalln(err)
return err
}
manifest, err := hub.Manifest(repoPart, tagPart)
if err != nil {
jww.ERROR.Fatalln(err)
return err
}
layers := manifest.FSLayers
layers_sha := make([]string, 0)
for _, l := range layers {
jww.INFO.Println("Layer ", l)
// or obtain the digest from an existing manifest's FSLayer list
s := string(l.BlobSum)
i := strings.Index(s, ":")
enc := s[i+1:]
reader, err := hub.DownloadBlob(repoPart, l.BlobSum)
layers_sha = append(layers_sha, enc)
if reader != nil {
defer reader.Close()
}
if err != nil {
return err
}
where := path.Join(TempDir, enc)
err = os.MkdirAll(where, os.ModePerm)
if err != nil {
jww.ERROR.Println(err)
return err
}
out, err := os.Create(path.Join(where, "layer.tar"))
if err != nil {
return err
}
defer out.Close()
if _, err := io.Copy(out, reader); err != nil {
fmt.Println(err)
return err
}
}
jww.INFO.Println("Download complete")
export, err := CreateExport(TempDir)
if err != nil {
fmt.Println(err)
return err
}
jww.INFO.Println("Unpacking...")
err = export.UnPackLayers(layers_sha, output, opts.UnpackMode)
if err != nil {
jww.INFO.Fatal(err)
return err
}
jww.INFO.Println("Done")
return nil
}
func CreateExport(layers string) (*Export, error) {
export := &Export{
Entries: map[string]*ExportedImage{},
Path: layers,
}
dirs, err := ioutil.ReadDir(export.Path)
if err != nil {
return nil, err
}
for _, dir := range dirs {
if !dir.IsDir() {
continue
}
entry := &ExportedImage{
Path: filepath.Join(export.Path, dir.Name()),
LayerTarPath: filepath.Join(export.Path, dir.Name(), "layer.tar"),
LayerDirPath: filepath.Join(export.Path, dir.Name(), "layer"),
}
export.Entries[dir.Name()] = entry
}
return export, err
}