mirror of
https://github.com/mudler/luet.git
synced 2025-09-09 11:10:07 +00:00
Switch to go mod
This commit is contained in:
155
vendor/github.com/mudler/docker-companion/api/download.go
generated
vendored
Normal file
155
vendor/github.com/mudler/docker-companion/api/download.go
generated
vendored
Normal 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
|
||||
}
|
94
vendor/github.com/mudler/docker-companion/api/export.go
generated
vendored
Normal file
94
vendor/github.com/mudler/docker-companion/api/export.go
generated
vendored
Normal 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
67
vendor/github.com/mudler/docker-companion/api/image.go
generated
vendored
Normal 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
|
||||
}
|
92
vendor/github.com/mudler/docker-companion/api/squash.go
generated
vendored
Normal file
92
vendor/github.com/mudler/docker-companion/api/squash.go
generated
vendored
Normal 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
157
vendor/github.com/mudler/docker-companion/api/unpack.go
generated
vendored
Normal 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
80
vendor/github.com/mudler/docker-companion/api/util.go
generated
vendored
Normal 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
|
||||
}
|
Reference in New Issue
Block a user