diff --git a/.gitignore b/.gitignore index 2dc576d..6e17878 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ scratch bin/ dist/ images +wstation diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e003b64..c7d1015 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -15,6 +15,7 @@ project_name: d2vm before: hooks: - go mod tidy + - go generate ./... builds: - main: ./cmd/d2vm env: diff --git a/Makefile b/Makefile index 3387b0c..843f9cb 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,7 @@ vet: @go list ./...|grep -v scratch|GOOS=linux xargs go vet .build: + @go generate ./... @go build -o d2vm -ldflags "-s -w -X '$(MODULE).Version=$(VERSION)' -X '$(MODULE).BuildDate=$(shell date)'" ./cmd/d2vm .PHONY: build-snapshot diff --git a/builder.go b/builder.go index b205481..b50b181 100644 --- a/builder.go +++ b/builder.go @@ -87,6 +87,24 @@ const ( perm os.FileMode = 0644 ) +func sysconfig(osRelease OSRelease) (string, error) { + switch osRelease.ID { + case ReleaseUbuntu: + if osRelease.VersionID < "20.04" { + return syslinuxCfgDebian, nil + } + return syslinuxCfgUbuntu, nil + case ReleaseDebian: + return syslinuxCfgDebian, nil + case ReleaseAlpine: + return syslinuxCfgAlpine, nil + case ReleaseCentOS: + return syslinuxCfgCentOS, nil + default: + return "", fmt.Errorf("%s: distribution not supported", osRelease.ID) + } +} + type builder struct { osRelease OSRelease @@ -321,22 +339,9 @@ func (b *builder) installKernel(ctx context.Context) error { if err := exec.Run(ctx, "extlinux", "--install", b.chPath("/boot")); err != nil { return err } - var sysconfig string - switch b.osRelease.ID { - case ReleaseUbuntu: - if b.osRelease.VersionID < "20.04" { - sysconfig = syslinuxCfgDebian - } else { - sysconfig = syslinuxCfgUbuntu - } - case ReleaseDebian: - sysconfig = syslinuxCfgDebian - case ReleaseAlpine: - sysconfig = syslinuxCfgAlpine - case ReleaseCentOS: - sysconfig = syslinuxCfgCentOS - default: - return fmt.Errorf("%s: distribution not supported", b.osRelease.ID) + sysconfig, err := sysconfig(b.osRelease) + if err != nil { + return err } if err := b.chWriteFile("/boot/syslinux.cfg", fmt.Sprintf(sysconfig, b.diskUUD), perm); err != nil { return err diff --git a/builder_test.go b/builder_test.go new file mode 100644 index 0000000..b00bca3 --- /dev/null +++ b/builder_test.go @@ -0,0 +1,136 @@ +package d2vm + +import ( + "context" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.linka.cloud/d2vm/pkg/docker" + "go.linka.cloud/d2vm/pkg/exec" +) + +func testSysconfig(t *testing.T, ctx context.Context, img, sysconf, kernel, initrd string) { + tmpPath := filepath.Join(os.TempDir(), "d2vm-tests", strings.NewReplacer(":", "-", ".", "-").Replace(img)) + require.NoError(t, os.MkdirAll(tmpPath, 0755)) + defer os.RemoveAll(tmpPath) + logrus.Infof("inspecting image %s", img) + r, err := FetchDockerImageOSRelease(ctx, img, tmpPath) + require.NoError(t, err) + defer docker.Remove(ctx, img) + sys, err := sysconfig(r) + require.NoError(t, err) + assert.Equal(t, sysconf, sys) + d, err := NewDockerfile(r, img, "root") + require.NoError(t, err) + logrus.Infof("docker image based on %s", d.Release.Name) + p := filepath.Join(tmpPath, docker.FormatImgName(img)) + dir := filepath.Dir(p) + f, err := os.Create(p) + require.NoError(t, err) + defer f.Close() + require.NoError(t, d.Render(f)) + imgUUID := uuid.New().String() + logrus.Infof("building kernel enabled image") + require.NoError(t, docker.Build(ctx, imgUUID, p, dir)) + defer docker.Remove(ctx, imgUUID) + require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", kernel)) + require.NoError(t, docker.RunAndRemove(ctx, imgUUID, "test", "-f", initrd)) +} + +func TestSyslinuxCfg(t *testing.T) { + tests := []struct { + image string + kernel string + initrd string + sysconfig string + }{ + { + image: "ubuntu:18.04", + kernel: "/vmlinuz", + initrd: "/initrd.img", + sysconfig: syslinuxCfgDebian, + }, + { + image: "ubuntu:20.04", + kernel: "/boot/vmlinuz", + initrd: "/boot/initrd.img", + sysconfig: syslinuxCfgUbuntu, + }, + { + image: "ubuntu:22.04", + kernel: "/boot/vmlinuz", + initrd: "/boot/initrd.img", + sysconfig: syslinuxCfgUbuntu, + }, + { + image: "ubuntu:latest", + kernel: "/boot/vmlinuz", + initrd: "/boot/initrd.img", + sysconfig: syslinuxCfgUbuntu, + }, + { + image: "debian:8", + kernel: "/vmlinuz", + initrd: "/initrd.img", + sysconfig: syslinuxCfgDebian, + }, + { + image: "debian:9", + kernel: "/vmlinuz", + initrd: "/initrd.img", + sysconfig: syslinuxCfgDebian, + }, + { + image: "debian:10", + kernel: "/vmlinuz", + initrd: "/initrd.img", + sysconfig: syslinuxCfgDebian, + }, + { + image: "debian:11", + kernel: "/vmlinuz", + initrd: "/initrd.img", + sysconfig: syslinuxCfgDebian, + }, + { + image: "debian:latest", + kernel: "/vmlinuz", + initrd: "/initrd.img", + sysconfig: syslinuxCfgDebian, + }, + { + image: "alpine", + kernel: "/boot/vmlinuz-virt", + initrd: "/boot/initramfs-virt", + sysconfig: syslinuxCfgAlpine, + }, + { + image: "centos:8", + kernel: "/boot/vmlinuz", + initrd: "/boot/initrd.img", + sysconfig: syslinuxCfgCentOS, + }, + { + image: "centos:latest", + kernel: "/boot/vmlinuz", + initrd: "/boot/initrd.img", + sysconfig: syslinuxCfgCentOS, + }, + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + exec.SetDebug(true) + + for _, test := range tests { + t.Run(test.image, func(t *testing.T) { + testSysconfig(t, ctx, test.image, test.sysconfig, test.kernel, test.initrd) + }) + } +} diff --git a/cmd/d2vm/main.go b/cmd/d2vm/main.go index 85f0427..c54fb90 100644 --- a/cmd/d2vm/main.go +++ b/cmd/d2vm/main.go @@ -16,6 +16,9 @@ package main import ( "context" + "fmt" + "os" + "os/signal" "github.com/spf13/cobra" @@ -41,5 +44,12 @@ func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, os.Interrupt, os.Kill) + go func() { + <-sigs + fmt.Println() + cancel() + }() rootCmd.ExecuteContext(ctx) } diff --git a/cmd/d2vm/run.go b/cmd/d2vm/run.go index 9643f9e..10c62bf 100644 --- a/cmd/d2vm/run.go +++ b/cmd/d2vm/run.go @@ -38,5 +38,6 @@ func init() { runCmd.AddCommand(run.VboxCmd) runCmd.AddCommand(run.QemuCmd) + runCmd.AddCommand(run.HetznerCmd) runCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Enable Debug output") } diff --git a/cmd/d2vm/run/hetzner.go b/cmd/d2vm/run/hetzner.go new file mode 100644 index 0000000..fba30da --- /dev/null +++ b/cmd/d2vm/run/hetzner.go @@ -0,0 +1,229 @@ +package run + +import ( + "bytes" + "context" + "fmt" + "io" + "os" + "os/exec" + "strings" + "time" + + "github.com/dustin/go-humanize" + "github.com/hetznercloud/hcloud-go/hcloud" + "github.com/pkg/sftp" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/svenwiltink/sparsecat" +) + +const ( + serverImg = "ubuntu-20.04" +) + +var ( + hetznerVMType = "cx11" + hetznerToken = "" + // ash-dc1 fsn1-dc14 hel1-dc2 nbg1-dc3 + hetznerDatacenter = "hel1-dc2" + hetznerServerName = "d2vm" + hetznerSSHUser = "" + hetznerSSHKeyPath = "" + hetznerRemove = false + + HetznerCmd = &cobra.Command{ + Use: "hetzner [options] image-path", + Args: cobra.ExactArgs(1), + Run: Hetzner, + } +) + +func init() { + HetznerCmd.Flags().StringVarP(&hetznerToken, "token", "t", "", "Hetzner Cloud API token") + HetznerCmd.Flags().StringVarP(&hetznerSSHUser, "user", "u", "root", "d2vm image ssh user") + HetznerCmd.Flags().StringVarP(&hetznerSSHKeyPath, "ssh-key", "i", "", "d2vm image identity key") + HetznerCmd.Flags().BoolVar(&hetznerRemove, "rm", false, "remove server when done") + HetznerCmd.Flags().StringVarP(&hetznerServerName, "name", "n", "d2vm", "d2vm server name") +} + +func Hetzner(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithCancel(cmd.Context()) + defer cancel() + if err := runHetzner(ctx, args[0], cmd.InOrStdin(), cmd.ErrOrStderr(), cmd.OutOrStdout()); err != nil { + logrus.Fatal(err) + } +} + +func runHetzner(ctx context.Context, imgPath string, stdin io.Reader, stderr io.Writer, stdout io.Writer) error { + i, err := ImgInfo(ctx, imgPath) + if err != nil { + return err + } + if i.Format != "raw" { + return fmt.Errorf("image format must be raw") + } + src, err := os.Open(imgPath) + if err != nil { + return err + } + defer src.Close() + // TODO(adphi): check image format + // TODO(adphi): convert to raw if needed + + c := hcloud.NewClient(hcloud.WithToken(hetznerToken)) + st, _, err := c.ServerType.GetByName(ctx, hetznerVMType) + if err != nil { + return err + } + img, _, err := c.Image.GetByName(ctx, serverImg) + if err != nil { + return err + } + l, _, err := c.Location.Get(ctx, hetznerDatacenter) + if err != nil { + return err + } + logrus.Infof("creating server %s", hetznerServerName) + sres, _, err := c.Server.Create(ctx, hcloud.ServerCreateOpts{ + Name: hetznerServerName, + ServerType: st, + Image: img, + Location: l, + StartAfterCreate: hcloud.Bool(false), + }) + if err != nil { + return err + } + _, errs := c.Action.WatchProgress(ctx, sres.Action) + if err := <-errs; err != nil { + return err + } + remove := true + defer func() { + if !remove && !hetznerRemove { + return + } + logrus.Infof("removing server %s", hetznerServerName) + // we use context.Background() here because we don't want the request to fail if the context has been cancelled + if _, err := c.Server.Delete(context.Background(), sres.Server); err != nil { + logrus.Fatalf("failed to remove server: %v", err) + } + }() + logrus.Infof("server created with ip: %s", sres.Server.PublicNet.IPv4.IP.String()) + logrus.Infof("enabling server rescue mode") + rres, _, err := c.Server.EnableRescue(ctx, sres.Server, hcloud.ServerEnableRescueOpts{Type: hcloud.ServerRescueTypeLinux64}) + if err != nil { + return err + } + _, errs = c.Action.WatchProgress(ctx, rres.Action) + if err := <-errs; err != nil { + return err + } + logrus.Infof("powering on server") + pres, _, err := c.Server.Poweron(ctx, sres.Server) + if err != nil { + return err + } + _, errs = c.Action.WatchProgress(ctx, pres) + if err := <-errs; err != nil { + return err + } + logrus.Infof("connecting to server via ssh") + sc, err := dialSSHWithTimeout(sres.Server.PublicNet.IPv4.IP.String(), "root", rres.RootPassword, time.Minute) + if err != nil { + return err + } + defer sc.Close() + logrus.Infof("connection established") + sftpc, err := sftp.NewClient(sc) + if err != nil { + return err + } + f, err := sftpc.Create("/usr/local/bin/sparsecat") + if err != nil { + return err + } + if err := sftpc.Chmod("/usr/local/bin/sparsecat", 0755); err != nil { + return err + } + defer f.Close() + if _, err := io.Copy(f, bytes.NewReader(sparsecatBinary)); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + wses, err := sc.NewSession() + if err != nil { + return err + } + defer wses.Close() + logrus.Infof("writing image to /dev/sda") + done := make(chan struct{}) + pr := newProgressReader(sparsecat.NewEncoder(src)) + wses.Stdin = pr + go func() { + tk := time.NewTicker(time.Second) + last := 0 + for { + select { + case <-tk.C: + b := pr.Progress() + logrus.Infof("%s / %d%% transfered ( %s/s)", humanize.Bytes(uint64(b)), int(float64(b)/float64(i.ActualSize)*100), humanize.Bytes(uint64(b-last))) + last = b + case <-ctx.Done(): + return + case <-done: + return + } + } + }() + if b, err := wses.CombinedOutput("/usr/local/bin/sparsecat -r -disable-sparse-target -of /dev/sda"); err != nil { + logrus.Fatalf("%v: %s", err, string(b)) + } + close(done) + logrus.Infof("rebooting server") + rbres, _, err := c.Server.Reboot(ctx, sres.Server) + if err != nil { + return err + } + _, errs = c.Action.WatchProgress(ctx, rbres) + if err := <-errs; err != nil { + return err + } + logrus.Infof("server created") + remove = false + args := []string{"-o", "StrictHostKeyChecking=no"} + if hetznerSSHKeyPath != "" { + args = append(args, "-i", hetznerSSHKeyPath) + } + args = append(args, fmt.Sprintf("%s@%s", hetznerSSHUser, sres.Server.PublicNet.IPv4.IP.String())) + makeCmd := func() *exec.Cmd { + cmd := exec.CommandContext(ctx, "ssh", args...) + cmd.Stdin = stdin + cmd.Stderr = stderr + cmd.Stdout = stdout + return cmd + } + t := time.NewTimer(time.Minute) + for { + select { + case <-t.C: + return fmt.Errorf("ssh connection timeout") + case <-ctx.Done(): + return ctx.Err() + default: + cmd := makeCmd() + if err := cmd.Run(); err != nil { + if strings.Contains(err.Error(), "exit status 255") { + time.Sleep(time.Second) + continue + } + return err + } else { + return nil + } + } + } +} diff --git a/cmd/d2vm/run/sparsecat-linux-amd64 b/cmd/d2vm/run/sparsecat-linux-amd64 new file mode 100755 index 0000000..bdf2fee Binary files /dev/null and b/cmd/d2vm/run/sparsecat-linux-amd64 differ diff --git a/cmd/d2vm/run/util.go b/cmd/d2vm/run/util.go index c6ea9b5..00df79f 100644 --- a/cmd/d2vm/run/util.go +++ b/cmd/d2vm/run/util.go @@ -1,3 +1,5 @@ +//go:generate env GOOS=linux GOARCH=amd64 go build -o sparsecat-linux-amd64 github.com/svenwiltink/sparsecat/cmd/sparsecat + // Copyright 2022 Linka Cloud All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,12 +18,24 @@ package run import ( "bufio" + "context" + _ "embed" + "encoding/json" "fmt" + "io" "os" + "os/exec" "strconv" "strings" + "sync" + "time" + + "golang.org/x/crypto/ssh" ) +//go:embed sparsecat-linux-amd64 +var sparsecatBinary []byte + // Handle flags with multiple occurrences type MultipleFlag []string @@ -274,3 +288,75 @@ func NewPublishedPort(publish string) (PublishedPort, error) { p.Protocol = protocol return p, nil } + +func dialSSH(server, user, password string) (*ssh.Client, error) { + c, err := ssh.Dial("tcp", server+":22", &ssh.ClientConfig{ + User: user, + Auth: []ssh.AuthMethod{ssh.Password(password)}, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + }) + if err != nil { + return nil, err + } + return c, nil +} + +func dialSSHWithTimeout(server, user, password string, timeout time.Duration) (*ssh.Client, error) { + t := time.NewTimer(timeout) + for { + select { + case <-t.C: + return nil, fmt.Errorf("timeout while trying to connect to the server") + default: + c, err := dialSSH(server, user, password) + if err == nil { + return c, nil + } + time.Sleep(time.Second) + } + } +} + +func newProgressReader(r io.Reader) *pw { + return &pw{r: r} +} + +type pw struct { + r io.Reader + total int + size int + mu sync.RWMutex +} + +func (p *pw) Read(buf []byte) (int, error) { + p.mu.Lock() + p.total += len(buf) + p.mu.Unlock() + return p.r.Read(buf) +} + +func (p *pw) Progress() int { + p.mu.RLock() + defer p.mu.RUnlock() + return p.total +} + +type QemuInfo struct { + VirtualSize int `json:"virtual-size"` + Filename string `json:"filename"` + Format string `json:"format"` + ActualSize int `json:"actual-size"` + DirtyFlag bool `json:"dirty-flag"` +} + +func ImgInfo(ctx context.Context, path string) (*QemuInfo, error) { + o, err := exec.CommandContext(ctx, "qemu-img", "info", path, "--output", "json").CombinedOutput() + if err != nil { + return nil, fmt.Errorf("%v: %s", err, string(o)) + } + var i QemuInfo + if err := json.Unmarshal(o, &i); err != nil { + return nil, err + } + return &i, nil +} diff --git a/docker_image.go b/docker_image.go index afb2183..94c998b 100644 --- a/docker_image.go +++ b/docker_image.go @@ -80,11 +80,6 @@ func (i DockerImage) AsRunScript(w io.Writer) error { return dockerImageRunTemplate.Execute(w, i) } -const ( - whiteoutPrefix = ".wh." - manifest = "manifest.json" -) - func NewImage(ctx context.Context, tag string, imageTmpPath string) (*image, error) { ref, err := name.ParseReference(tag) if err != nil { diff --git a/go.mod b/go.mod index 7e7c6a9..abcc403 100644 --- a/go.mod +++ b/go.mod @@ -5,18 +5,24 @@ go 1.17 require ( github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 github.com/containerd/console v1.0.3 + github.com/dustin/go-humanize v1.0.0 github.com/google/go-containerregistry v0.8.0 github.com/google/uuid v1.3.0 + github.com/hetznercloud/hcloud-go v1.35.2 github.com/joho/godotenv v1.4.0 + github.com/pkg/sftp v1.10.1 github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.4.0 github.com/stretchr/testify v1.7.0 github.com/svenwiltink/sparsecat v1.0.0 go.uber.org/multierr v1.8.0 + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 ) require ( github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/containerd/containerd v1.5.8 // indirect github.com/containerd/stargz-snapshotter/estargz v0.10.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -31,16 +37,24 @@ require ( github.com/google/go-cmp v0.5.6 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/klauspost/compress v1.13.6 // indirect + github.com/kr/fs v0.1.0 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.26.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/vbatts/tar-split v0.11.2 // indirect go.uber.org/atomic v1.7.0 // indirect + golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/text v0.3.7 // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect google.golang.org/grpc v1.43.0 // indirect google.golang.org/protobuf v1.27.1 // indirect diff --git a/go.sum b/go.sum index c37bb8b..fd3bd03 100644 --- a/go.sum +++ b/go.sum @@ -92,6 +92,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -105,6 +106,7 @@ github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZo github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= @@ -122,8 +124,10 @@ github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2/go.mod h1:S/7n9cop github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= @@ -295,6 +299,7 @@ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNE github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -329,8 +334,10 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= @@ -486,6 +493,8 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hetznercloud/hcloud-go v1.35.2 h1:eEDtmDiI2plZ2UQmj4YpiYse5XbtpXOUBpAdIOLxzgE= +github.com/hetznercloud/hcloud-go v1.35.2/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -503,6 +512,7 @@ github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -513,6 +523,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -524,6 +535,7 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -557,6 +569,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= @@ -589,6 +602,7 @@ github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -643,6 +657,7 @@ github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -656,10 +671,13 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= @@ -668,6 +686,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -678,6 +698,7 @@ github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -822,6 +843,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1001,6 +1023,7 @@ golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1031,6 +1054,7 @@ golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1046,6 +1070,7 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/docker/docker.go b/pkg/docker/docker.go index cc02294..5825ef7 100644 --- a/pkg/docker/docker.go +++ b/pkg/docker/docker.go @@ -92,6 +92,11 @@ func RunInteractiveAndRemove(ctx context.Context, args ...string) error { return cmd.Run() } +func RunAndRemove(ctx context.Context, args ...string) error { + logrus.Tracef("running 'docker run --rm %s'", strings.Join(args, " ")) + return Cmd(ctx, append([]string{"run", "--rm"}, args...)...) +} + func RunD2VM(ctx context.Context, image, version, cmd string, args ...string) error { pwd, err := os.Getwd() if err != nil {