Switch to go mod

This commit is contained in:
Ettore Di Giacinto
2019-11-10 18:04:06 +01:00
parent f634493dc0
commit 420186b7db
1200 changed files with 139110 additions and 7763 deletions

View File

@@ -0,0 +1,155 @@
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
}

View File

@@ -0,0 +1,94 @@
package api
// This part is an extract from https://github.com/jwilder/docker-squash/
import (
"os"
"path"
"path/filepath"
"strings"
jww "github.com/spf13/jwalterweatherman"
)
type Export struct {
Entries map[string]*ExportedImage
Path string
}
func (e *Export) ExtractLayers(unpackmode string) error {
jww.INFO.Println("Extracting layers...")
for _, entry := range e.Entries {
jww.INFO.Println(" - ", entry.LayerTarPath)
err := entry.ExtractLayerDir(unpackmode)
if err != nil {
return err
}
}
return nil
}
func (e *Export) UnPackLayers(order []string, layerDir string, unpackmode string) error {
err := os.MkdirAll(layerDir, 0755)
if err != nil {
return err
}
for _, ee := range order {
entry := e.Entries[ee]
if _, err := os.Stat(entry.LayerTarPath); os.IsNotExist(err) {
continue
}
err := ExtractLayer(&ExtractOpts{
Source: entry.LayerTarPath,
Destination: layerDir,
Compressed: true,
KeepDirlinks: true,
Rootless: false,
UnpackMode: unpackmode})
if err != nil {
jww.INFO.Println(err.Error())
return err
}
jww.INFO.Println(" - Deleting whiteouts for layer " + ee)
err = e.deleteWhiteouts(layerDir)
if err != nil {
return err
}
}
return nil
}
const TarCmd = "tar"
func (e *Export) deleteWhiteouts(location string) error {
return filepath.Walk(location, func(p string, info os.FileInfo, err error) error {
if err != nil && !os.IsNotExist(err) {
return err
}
if info == nil {
return nil
}
name := info.Name()
parent := filepath.Dir(p)
// if start with whiteout
if strings.Index(name, ".wh.") == 0 {
deletedFile := path.Join(parent, name[len(".wh."):len(name)])
// remove deleted files
if err := os.RemoveAll(deletedFile); err != nil {
return err
}
// remove the whiteout itself
if err := os.RemoveAll(p); err != nil {
return err
}
}
return nil
})
}

67
vendor/github.com/mudler/docker-companion/api/image.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
package api
// This part is an extract from https://github.com/jwilder/docker-squash/
import (
"fmt"
"os"
jww "github.com/spf13/jwalterweatherman"
"os/exec"
)
type ExportedImage struct {
Path string
JsonPath string
VersionPath string
LayerTarPath string
LayerDirPath string
}
func (e *ExportedImage) CreateDirs() error {
return os.MkdirAll(e.Path, 0755)
}
func (e *ExportedImage) TarLayer() error {
cwd, err := os.Getwd()
if err != nil {
return err
}
err = os.Chdir(e.LayerDirPath)
if err != nil {
return err
}
defer os.Chdir(cwd)
cmd := exec.Command("sudo", "/bin/sh", "-c", fmt.Sprintf("%s cvf ../layer.tar ./", TarCmd))
out, err := cmd.CombinedOutput()
if err != nil {
jww.INFO.Println(out)
return err
}
return nil
}
func (e *ExportedImage) RemoveLayerDir() error {
return os.RemoveAll(e.LayerDirPath)
}
func (e *ExportedImage) ExtractLayerDir(unpackmode string) error {
err := os.MkdirAll(e.LayerDirPath, 0755)
if err != nil {
return err
}
if err := ExtractLayer(&ExtractOpts{
Source: e.LayerTarPath,
Destination: e.LayerDirPath,
Compressed: true,
KeepDirlinks: true,
Rootless: false,
UnpackMode: unpackmode}); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,92 @@
package api
import (
"fmt"
"io"
"os"
"os/signal"
"strings"
"syscall"
"github.com/fsouza/go-dockerclient"
jww "github.com/spf13/jwalterweatherman"
)
// Squash Squashes a docker image into another one
func Squash(client *docker.Client, image string, toImage string) error {
var err error
var Tag = "latest"
r, w := io.Pipe()
Imageparts := strings.Split(toImage, ":")
if len(Imageparts) == 2 {
Tag = Imageparts[1]
toImage = Imageparts[0]
}
jww.INFO.Println("Creating container")
container, err := client.CreateContainer(docker.CreateContainerOptions{
Config: &docker.Config{
Image: image,
Cmd: []string{"true"},
},
})
if err != nil {
jww.FATAL.Fatalln("Couldn't create container, sorry", err)
}
defer func(*docker.Container) {
client.RemoveContainer(docker.RemoveContainerOptions{
ID: container.ID,
Force: true,
})
}(container)
signalchan := make(chan os.Signal, 1)
signal.Notify(signalchan,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
go func() {
for {
s := <-signalchan
switch s {
case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
jww.WARN.Println("SIGTERM/SIGINT/SIGQUIT detected, removing pending containers/image")
client.RemoveContainer(docker.RemoveContainerOptions{
ID: container.ID,
Force: true,
})
client.RemoveImage(toImage)
}
}
}()
// writing without a reader will deadlock so write in a goroutine
go func() {
// it is important to close the writer or reading from the other end of the
// pipe will never finish
defer w.Close()
err = client.ExportContainer(docker.ExportContainerOptions{ID: container.ID, OutputStream: w})
if err != nil {
jww.FATAL.Fatalln("Couldn't export container, sorry", err)
}
}()
jww.INFO.Println("Importing to", toImage)
err = client.ImportImage(docker.ImportImageOptions{Repository: toImage,
Source: "-",
InputStream: r,
Tag: Tag,
})
if err != nil {
return fmt.Errorf("Could not import docker image")
}
return nil
}

157
vendor/github.com/mudler/docker-companion/api/unpack.go generated vendored Normal file
View File

@@ -0,0 +1,157 @@
package api
import (
"fmt"
"io"
"io/ioutil"
"os"
"os/signal"
"path/filepath"
"syscall"
"github.com/docker/docker/pkg/archive"
docker "github.com/fsouza/go-dockerclient"
jww "github.com/spf13/jwalterweatherman"
)
// SEPARATOR contains system-specific separator
const SEPARATOR = string(filepath.Separator)
// ROOTFS is our temporary rootfs path
const ROOTFS = "." + SEPARATOR + "rootfs_overlay"
// Unpack unpacks a docker image into a path
func Unpack(client *docker.Client, image string, dirname string, fatal bool) error {
var err error
r, w := io.Pipe()
if dirname == "" {
dirname = ROOTFS
}
os.MkdirAll(dirname, 0777)
filename, err := ioutil.TempFile(os.TempDir(), "artemide")
if err != nil {
return fmt.Errorf("Couldn't create the temporary file")
}
os.Remove(filename.Name())
jww.INFO.Println("Creating container")
container, err := client.CreateContainer(docker.CreateContainerOptions{
Config: &docker.Config{
Image: image,
Cmd: []string{"true"},
},
})
if err != nil {
jww.FATAL.Fatalln("Couldn't export container, sorry", err)
}
defer func(*docker.Container) {
client.RemoveContainer(docker.RemoveContainerOptions{
ID: container.ID,
Force: true,
})
}(container)
signalchan := make(chan os.Signal, 1)
signal.Notify(signalchan,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT)
go func() {
for {
s := <-signalchan
switch s {
case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
jww.WARN.Println("SIGTERM/SIGINT/SIGQUIT detected, removing pending containers")
client.RemoveContainer(docker.RemoveContainerOptions{
ID: container.ID,
Force: true,
})
}
}
}()
// writing without a reader will deadlock so write in a goroutine
go func() {
// it is important to close the writer or reading from the other end of the
// pipe will never finish
defer w.Close()
err := client.ExportContainer(docker.ExportContainerOptions{ID: container.ID, OutputStream: w})
if err != nil {
jww.FATAL.Fatalln("Couldn't export container, sorry", err)
}
}()
jww.INFO.Println("Extracting to", dirname)
err = Untar(r, dirname, true)
if err != nil {
return fmt.Errorf("could not unpack to " + dirname)
}
err = prepareRootfs(dirname, fatal)
return err
}
func prepareRootfs(dirname string, fatal bool) error {
_, err := os.Stat(dirname + SEPARATOR + ".dockerenv")
if err == nil {
err = os.Remove(dirname + SEPARATOR + ".dockerenv")
if err != nil {
if fatal == true {
return fmt.Errorf("could not remove docker env file")
} else {
jww.WARN.Println("error on remove .dockerenv, extracting anyway")
}
}
}
_, err = os.Stat(dirname + SEPARATOR + ".dockerinit")
if err == nil {
err = os.Remove(dirname + SEPARATOR + ".dockerinit")
if err != nil {
if fatal == true {
return fmt.Errorf("could not remove docker init file")
} else {
jww.WARN.Println("error on remove .dockerinit, extracting anyway")
}
}
}
err = os.MkdirAll(dirname+SEPARATOR+"dev", 0751)
if err != nil {
if fatal == true {
return fmt.Errorf("could not create dev folder")
} else {
jww.WARN.Println("could not create dev folder")
}
}
// Google DNS as default
d1 := []byte("nameserver 8.8.8.8\nnameserver 8.8.4.4\n")
err = ioutil.WriteFile(dirname+SEPARATOR+"etc"+SEPARATOR+"resolv.conf", d1, 0644)
if err != nil {
if fatal == true {
return fmt.Errorf("could not write resolv.conf file")
} else {
jww.WARN.Println("could not create resolv.conf file")
}
}
return nil
}
// Untar just a wrapper around the docker functions
func Untar(in io.Reader, dest string, sameOwner bool) error {
return archive.Untar(in, dest, &archive.TarOptions{
NoLchown: !sameOwner,
ExcludePatterns: []string{"dev/"}, // prevent 'operation not permitted'
})
}

80
vendor/github.com/mudler/docker-companion/api/util.go generated vendored Normal file
View File

@@ -0,0 +1,80 @@
package api
import (
"bufio"
"context"
"io"
"os"
"github.com/urfave/cli"
archive "github.com/containerd/containerd/archive"
dockerarchive "github.com/docker/docker/pkg/archive"
docker "github.com/fsouza/go-dockerclient"
layer "github.com/openSUSE/umoci/oci/layer"
jww "github.com/spf13/jwalterweatherman"
)
type ExtractOpts struct {
Source, Destination string
Compressed, KeepDirlinks, Rootless bool
UnpackMode string
}
func ExtractLayer(opts *ExtractOpts) error {
file, err := os.Open(opts.Source)
if err != nil {
return err
}
var r io.Reader
r = file
if opts.Compressed {
decompressedArchive, err := dockerarchive.DecompressStream(bufio.NewReader(file))
if err != nil {
return err
}
defer decompressedArchive.Close()
r = decompressedArchive
}
buf := bufio.NewReader(r)
switch opts.UnpackMode {
case "umoci": // more fixes are in there
return layer.UnpackLayer(opts.Destination, buf, &layer.MapOptions{KeepDirlinks: opts.KeepDirlinks, Rootless: opts.Rootless})
case "containerd": // more cross-compatible
_, err := archive.Apply(context.Background(), opts.Destination, buf)
return err
default: // moby way
return Untar(buf, opts.Destination, !opts.Compressed)
}
}
// PullImage pull the specified image
func PullImage(client *docker.Client, image string) error {
var err error
// Pulling the image
jww.INFO.Printf("Pulling the docker image %s\n", image)
if err = client.PullImage(docker.PullImageOptions{Repository: image}, docker.AuthConfiguration{}); err != nil {
jww.ERROR.Printf("error pulling %s image: %s\n", image, err)
return err
}
jww.INFO.Println("Image", image, "pulled correctly")
return nil
}
// NewDocker Creates a new instance of *docker.Client, respecting env settings
func NewDocker() (*docker.Client, error) {
var err error
var client *docker.Client
if os.Getenv("DOCKER_SOCKET") != "" {
client, err = docker.NewClient(os.Getenv("DOCKER_SOCKET"))
} else {
client, err = docker.NewClient("unix:///var/run/docker.sock")
}
if err != nil {
return nil, cli.NewExitError("could not connect to the Docker daemon", 87)
}
return client, nil
}