summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--builder.go21
-rw-r--r--builder_test.go16
-rw-r--r--cmd/imagebuilder/imagebuilder.go54
-rw-r--r--debian/changelog6
-rw-r--r--debian/gitlab-ci.yml6
-rw-r--r--debian/patches/add-mounts-to-dispatch-run.patch107
-rw-r--r--debian/patches/series1
-rw-r--r--dispatchers.go110
-rw-r--r--dispatchers_test.go23
-rw-r--r--dockerclient/archive.go324
-rw-r--r--dockerclient/archive_112.go11
-rw-r--r--dockerclient/archive_113.go12
-rw-r--r--dockerclient/archive_test.go54
-rw-r--r--dockerclient/client.go454
-rw-r--r--dockerclient/client_112.go11
-rw-r--r--dockerclient/client_113.go12
-rw-r--r--dockerclient/conformance_test.go406
-rw-r--r--dockerclient/conformance_unix_test.go20
-rw-r--r--dockerclient/conformance_windows_test.go14
-rw-r--r--dockerclient/copyinfo.go3
-rw-r--r--dockerclient/copyinfo_test.go2
-rw-r--r--dockerclient/testdata/Dockerfile.copyfrom_135
-rw-r--r--dockerclient/testdata/Dockerfile.copyfrom_145
-rw-r--r--dockerclient/testdata/Dockerfile.multistage24
-rw-r--r--dockerclient/testdata/add/Dockerfile5
-rw-r--r--dockerclient/testdata/add/Dockerfile.addslash2
-rw-r--r--dockerclient/testdata/copychown/Dockerfile28
-rw-r--r--dockerclient/testdata/copyfrom/Dockerfile11
-rw-r--r--dockerclient/testdata/multistage/Dockerfile.env15
-rw-r--r--go.mod18
-rw-r--r--go.sum1003
-rw-r--r--imagebuilder.spec2
-rw-r--r--internals.go2
-rw-r--r--vendor.conf25
35 files changed, 2250 insertions, 566 deletions
diff --git a/.travis.yml b/.travis.yml
index 97b530b..ff6afee 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,8 @@
language: go
go:
- - "1.9"
- - "1.10"
+ - "1.16"
+ - "1.17"
install:
diff --git a/builder.go b/builder.go
index df52699..71dc41e 100644
--- a/builder.go
+++ b/builder.go
@@ -44,6 +44,7 @@ type Run struct {
type Executor interface {
Preserve(path string) error
EnsureContainerPath(path string) error
+ EnsureContainerPathAs(path, user string, mode *os.FileMode) error
Copy(excludes []string, copies ...Copy) error
Run(run Run, config docker.Config) error
UnrecognizedInstruction(step *Step) error
@@ -61,6 +62,15 @@ func (logExecutor) EnsureContainerPath(path string) error {
return nil
}
+func (logExecutor) EnsureContainerPathAs(path, user string, mode *os.FileMode) error {
+ if mode != nil {
+ log.Printf("ENSURE %s AS %q with MODE=%q", path, user, *mode)
+ } else {
+ log.Printf("ENSURE %s AS %q", path, user)
+ }
+ return nil
+}
+
func (logExecutor) Copy(excludes []string, copies ...Copy) error {
for _, c := range copies {
log.Printf("COPY %v -> %s (from:%s download:%t), chown: %s, chmod %s", c.Src, c.Dest, c.From, c.Download, c.Chown, c.Chmod)
@@ -88,6 +98,10 @@ func (noopExecutor) EnsureContainerPath(path string) error {
return nil
}
+func (noopExecutor) EnsureContainerPathAs(path, user string, mode *os.FileMode) error {
+ return nil
+}
+
func (noopExecutor) Copy(excludes []string, copies ...Copy) error {
return nil
}
@@ -303,6 +317,9 @@ type Builder struct {
PendingCopies []Copy
Warnings []string
+ // Raw platform string specified with `FROM --platform` of the stage
+ // It's up to the implementation or client to parse and use this field
+ Platform string
}
func NewBuilder(args map[string]string) *Builder {
@@ -375,7 +392,7 @@ func (b *Builder) Run(step *Step, exec Executor, noRunsRemaining bool) error {
}
if len(b.RunConfig.WorkingDir) > 0 {
- if err := exec.EnsureContainerPath(b.RunConfig.WorkingDir); err != nil {
+ if err := exec.EnsureContainerPathAs(b.RunConfig.WorkingDir, b.RunConfig.User, nil); err != nil {
return err
}
}
@@ -470,7 +487,7 @@ func (b *Builder) FromImage(image *docker.Image, node *parser.Node) error {
b.RunConfig.Env = nil
// Check to see if we have a default PATH, note that windows won't
- // have one as its set by HCS
+ // have one as it's set by HCS
if runtime.GOOS != "windows" && !hasEnvName(b.Env, "PATH") {
b.RunConfig.Env = append(b.RunConfig.Env, "PATH="+defaultPathEnv)
}
diff --git a/builder_test.go b/builder_test.go
index cf96a45..fa68eb0 100644
--- a/builder_test.go
+++ b/builder_test.go
@@ -328,6 +328,18 @@ func TestArgs(t *testing.T) {
expectedValue: "FOO=bar",
},
{
+ name: "multiple args in single step",
+ dockerfile: "FROM centos\nARG FOO=stuff WORLD=hello\n",
+ args: map[string]string{},
+ expectedValue: "WORLD=hello",
+ },
+ {
+ name: "multiple args in single step",
+ dockerfile: "FROM centos\nARG FOO=stuff WORLD=hello\n",
+ args: map[string]string{},
+ expectedValue: "FOO=stuff",
+ },
+ {
name: "headingArgRedefine",
dockerfile: "ARG FOO=stuff\nFROM centos\nARG FOO\n",
args: map[string]string{},
@@ -467,6 +479,10 @@ func (e *testExecutor) EnsureContainerPath(path string) error {
return e.Err
}
+func (e *testExecutor) EnsureContainerPathAs(path, user string, mode *os.FileMode) error {
+ return e.Err
+}
+
func (e *testExecutor) Copy(excludes []string, copies ...Copy) error {
e.Copies = append(e.Copies, copies...)
return e.Err
diff --git a/cmd/imagebuilder/imagebuilder.go b/cmd/imagebuilder/imagebuilder.go
index 22ddf8a..afeae69 100644
--- a/cmd/imagebuilder/imagebuilder.go
+++ b/cmd/imagebuilder/imagebuilder.go
@@ -8,6 +8,7 @@ import (
"path/filepath"
"strings"
+ "github.com/docker/distribution/reference"
dockertypes "github.com/docker/docker/api/types"
docker "github.com/fsouza/go-dockerclient"
"k8s.io/klog"
@@ -31,7 +32,7 @@ func main() {
var version bool
var mountSpecs stringSliceFlag
- VERSION := "1.2.1"
+ VERSION := "1.2.3"
arguments := stringMapFlag{}
flag.Var(&tags, "t", "The name to assign this image, if any. May be specified multiple times.")
@@ -87,7 +88,58 @@ func main() {
options.TransientMounts = mounts
options.Out, options.ErrOut = os.Stdout, os.Stderr
+ authConfigurations, err := docker.NewAuthConfigurationsFromDockerCfg()
+ if err != nil {
+ log.Fatalf("reading authentication configurations: %v", err)
+ }
+ if authConfigurations == nil {
+ klog.V(4).Infof("No authentication secrets found")
+ }
+
options.AuthFn = func(name string) ([]dockertypes.AuthConfig, bool) {
+ if authConfigurations != nil {
+ if authConfig, ok := authConfigurations.Configs[name]; ok {
+ klog.V(4).Infof("Found authentication secret for registry %q", name)
+ return []dockertypes.AuthConfig{{
+ Username: authConfig.Username,
+ Password: authConfig.Password,
+ Email: authConfig.Email,
+ ServerAddress: authConfig.ServerAddress,
+ }}, true
+ }
+ if named, err := reference.ParseNormalizedNamed(name); err == nil {
+ domain := reference.Domain(named)
+ if authConfig, ok := authConfigurations.Configs[domain]; ok {
+ klog.V(4).Infof("Found authentication secret for registry %q", domain)
+ return []dockertypes.AuthConfig{{
+ Username: authConfig.Username,
+ Password: authConfig.Password,
+ Email: authConfig.Email,
+ ServerAddress: authConfig.ServerAddress,
+ }}, true
+ }
+ if domain == "docker.io" || strings.HasSuffix(domain, ".docker.io") {
+ var auths []dockertypes.AuthConfig
+ for _, aka := range []string{"docker.io", "index.docker.io", "https://index.docker.io/v1/"} {
+ if aka == domain {
+ continue
+ }
+ if authConfig, ok := authConfigurations.Configs[aka]; ok {
+ klog.V(4).Infof("Found authentication secret for registry %q", aka)
+ auths = append(auths, dockertypes.AuthConfig{
+ Username: authConfig.Username,
+ Password: authConfig.Password,
+ Email: authConfig.Email,
+ ServerAddress: authConfig.ServerAddress,
+ })
+ }
+ }
+ if len(auths) > 0 {
+ return auths, true
+ }
+ }
+ }
+ }
return nil, false
}
options.LogFn = func(format string, args ...interface{}) {
diff --git a/debian/changelog b/debian/changelog
index 11fd700..a96eba3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-openshift-imagebuilder (1.2.3+ds1-1) unstable; urgency=medium
+
+ * New upstream release
+
+ -- Reinhard Tartler <siretart@tauware.de> Wed, 18 May 2022 22:04:00 -0400
+
golang-github-openshift-imagebuilder (1.2.1+ds1-3) unstable; urgency=medium
* Upload to unstable
diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
new file mode 100644
index 0000000..594e14e
--- /dev/null
+++ b/debian/gitlab-ci.yml
@@ -0,0 +1,6 @@
+# auto-generated, DO NOT MODIFY.
+# The authoritative copy of this file lives at:
+# https://salsa.debian.org/go-team/infra/pkg-go-tools/blob/master/config/gitlabciyml.go
+---
+include:
+ - https://salsa.debian.org/go-team/infra/pkg-go-tools/-/raw/master/pipeline/test-archive.yml
diff --git a/debian/patches/add-mounts-to-dispatch-run.patch b/debian/patches/add-mounts-to-dispatch-run.patch
deleted file mode 100644
index 26695d2..0000000
--- a/debian/patches/add-mounts-to-dispatch-run.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From e9fbbb5968e6e55095ed09fa7044bfa9d716aceb Mon Sep 17 00:00:00 2001
-From: Ashley Cui <acui@redhat.com>
-Date: Tue, 13 Apr 2021 14:58:56 -0400
-Subject: [PATCH] Add mounts to dispatch run
-
-parse build mounts RUN --mount=...
-the RUN command can take flags from the dockerfile.
-
-Signed-off-by: Ashley Cui <acui@redhat.com>
----
- builder.go | 4 +++-
- dispatchers.go | 21 ++++++++++++++++++++-
- dispatchers_test.go | 30 ++++++++++++++++++++++++++++++
- 3 files changed, 53 insertions(+), 2 deletions(-)
-
-diff --git a/builder.go b/builder.go
-index dd8b09c0..df526990 100644
---- a/builder.go
-+++ b/builder.go
-@@ -37,6 +37,8 @@ type Copy struct {
- type Run struct {
- Shell bool
- Args []string
-+ // Mounts are mounts specified through the --mount flag inside the Containerfile
-+ Mounts []string
- }
-
- type Executor interface {
-@@ -67,7 +69,7 @@ func (logExecutor) Copy(excludes []string, copies ...Copy) error {
- }
-
- func (logExecutor) Run(run Run, config docker.Config) error {
-- log.Printf("RUN %v %t (%v)", run.Args, run.Shell, config.Env)
-+ log.Printf("RUN %v %v %t (%v)", run.Args, run.Mounts, run.Shell, config.Env)
- return nil
- }
-
-diff --git a/dispatchers.go b/dispatchers.go
-index 2294ae0a..0d82136e 100644
---- a/dispatchers.go
-+++ b/dispatchers.go
-@@ -306,7 +306,26 @@ func run(b *Builder, args []string, attributes map[string]bool, flagArgs []strin
-
- args = handleJSONArgs(args, attributes)
-
-- run := Run{Args: args}
-+ var mounts []string
-+ userArgs := mergeEnv(envMapAsSlice(b.Args), b.Env)
-+ for _, a := range flagArgs {
-+ arg, err := ProcessWord(a, userArgs)
-+ if err != nil {
-+ return err
-+ }
-+ switch {
-+ case strings.HasPrefix(arg, "--mount="):
-+ mount := strings.TrimPrefix(arg, "--mount=")
-+ mounts = append(mounts, mount)
-+ default:
-+ return fmt.Errorf("RUN only supports the --mount flag")
-+ }
-+ }
-+
-+ run := Run{
-+ Args: args,
-+ Mounts: mounts,
-+ }
-
- if !attributes["json"] {
- run.Shell = true
-diff --git a/dispatchers_test.go b/dispatchers_test.go
-index 2a99c107..71c3d6a1 100644
---- a/dispatchers_test.go
-+++ b/dispatchers_test.go
-@@ -630,3 +630,33 @@ func TestDispatchAddChmod(t *testing.T) {
- t.Errorf("Expected %v, to match %v\n", expectedPendingCopies, mybuilder2.PendingCopies)
- }
- }
-+
-+func TestDispatchRunFlags(t *testing.T) {
-+ mybuilder := Builder{
-+ RunConfig: docker.Config{
-+ WorkingDir: "/root",
-+ Cmd: []string{"/bin/sh"},
-+ Image: "busybox",
-+ },
-+ }
-+
-+ flags := []string{"--mount=type=bind,target=/foo"}
-+ args := []string{"echo \"stuff\""}
-+ original := "RUN --mount=type=bind,target=/foo echo \"stuff\""
-+
-+ if err := run(&mybuilder, args, nil, flags, original); err != nil {
-+ t.Errorf("dispatchAdd error: %v", err)
-+ }
-+ expectedPendingRuns := []Run{
-+ {
-+ Shell: true,
-+ Args: args,
-+ Mounts: []string{"type=bind,target=/foo"},
-+ },
-+ }
-+
-+ if !reflect.DeepEqual(mybuilder.PendingRuns, expectedPendingRuns) {
-+ t.Errorf("Expected %v, to match %v\n", expectedPendingRuns, mybuilder.PendingRuns)
-+ }
-+
-+}
diff --git a/debian/patches/series b/debian/patches/series
index 0dab599..4024b8f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,2 @@
ftbfs-arm.patch
klog.patch
-add-mounts-to-dispatch-run.patch
diff --git a/dispatchers.go b/dispatchers.go
index 0d82136..fd05f03 100644
--- a/dispatchers.go
+++ b/dispatchers.go
@@ -234,6 +234,20 @@ func from(b *Builder, args []string, attributes map[string]bool, flagArgs []stri
return fmt.Errorf("Windows does not support FROM scratch")
}
}
+ userArgs := mergeEnv(envMapAsSlice(b.Args), b.Env)
+ for _, a := range flagArgs {
+ arg, err := ProcessWord(a, userArgs)
+ if err != nil {
+ return err
+ }
+ switch {
+ case strings.HasPrefix(arg, "--platform="):
+ platformString := strings.TrimPrefix(arg, "--platform=")
+ b.Platform = platformString
+ default:
+ return fmt.Errorf("FROM only supports the --platform flag")
+ }
+ }
b.RunConfig.Image = name
// TODO: handle onbuild
return nil
@@ -573,65 +587,63 @@ var targetArgs = []string{"TARGETOS", "TARGETARCH", "TARGETVARIANT"}
// to builder using the --build-arg flag for expansion/subsitution or passing to 'run'.
// Dockerfile author may optionally set a default value of this variable.
func arg(b *Builder, args []string, attributes map[string]bool, flagArgs []string, original string) error {
- if len(args) != 1 {
- return fmt.Errorf("ARG requires exactly one argument definition")
- }
-
var (
name string
value string
hasDefault bool
)
- arg := args[0]
- // 'arg' can just be a name or name-value pair. Note that this is different
- // from 'env' that handles the split of name and value at the parser level.
- // The reason for doing it differently for 'arg' is that we support just
- // defining an arg and not assign it a value (while 'env' always expects a
- // name-value pair). If possible, it will be good to harmonize the two.
- if strings.Contains(arg, "=") {
- parts := strings.SplitN(arg, "=", 2)
- name = parts[0]
- value = parts[1]
- hasDefault = true
- if name == "TARGETPLATFORM" {
- p, err := platforms.Parse(value)
- if err != nil {
- return fmt.Errorf("error parsing TARGETPLATFORM argument")
- }
- for _, val := range targetArgs {
- b.AllowedArgs[val] = true
- }
- b.Args["TARGETPLATFORM"] = p.OS + "/" + p.Architecture
- b.Args["TARGETOS"] = p.OS
- b.Args["TARGETARCH"] = p.Architecture
- b.Args["TARGETVARIANT"] = p.Variant
- if p.Variant != "" {
- b.Args["TARGETPLATFORM"] = b.Args["TARGETPLATFORM"] + "/" + p.Variant
+ for _, argument := range args {
+ arg := argument
+ // 'arg' can just be a name or name-value pair. Note that this is different
+ // from 'env' that handles the split of name and value at the parser level.
+ // The reason for doing it differently for 'arg' is that we support just
+ // defining an arg and not assign it a value (while 'env' always expects a
+ // name-value pair). If possible, it will be good to harmonize the two.
+ if strings.Contains(arg, "=") {
+ parts := strings.SplitN(arg, "=", 2)
+ name = parts[0]
+ value = parts[1]
+ hasDefault = true
+ if name == "TARGETPLATFORM" {
+ p, err := platforms.Parse(value)
+ if err != nil {
+ return fmt.Errorf("error parsing TARGETPLATFORM argument")
+ }
+ for _, val := range targetArgs {
+ b.AllowedArgs[val] = true
+ }
+ b.Args["TARGETPLATFORM"] = p.OS + "/" + p.Architecture
+ b.Args["TARGETOS"] = p.OS
+ b.Args["TARGETARCH"] = p.Architecture
+ b.Args["TARGETVARIANT"] = p.Variant
+ if p.Variant != "" {
+ b.Args["TARGETPLATFORM"] = b.Args["TARGETPLATFORM"] + "/" + p.Variant
+ }
}
+ } else if val, ok := builtinBuildArgs[arg]; ok {
+ name = arg
+ value = val
+ hasDefault = true
+ } else {
+ name = arg
+ hasDefault = false
}
- } else if val, ok := builtinBuildArgs[arg]; ok {
- name = arg
- value = val
- hasDefault = true
- } else {
- name = arg
- hasDefault = false
- }
- // add the arg to allowed list of build-time args from this step on.
- b.AllowedArgs[name] = true
+ // add the arg to allowed list of build-time args from this step on.
+ b.AllowedArgs[name] = true
- // If there is still no default value, a value can be assigned from the heading args
- if val, ok := b.HeadingArgs[name]; ok && !hasDefault {
- b.Args[name] = val
- }
+ // If there is still no default value, a value can be assigned from the heading args
+ if val, ok := b.HeadingArgs[name]; ok && !hasDefault {
+ b.Args[name] = val
+ }
- // If there is a default value associated with this arg then add it to the
- // b.buildArgs, later default values for the same arg override earlier ones.
- // The args passed to builder (UserArgs) override the default value of 'arg'
- // Don't add them here as they were already set in NewBuilder.
- if _, ok := b.UserArgs[name]; !ok && hasDefault {
- b.Args[name] = value
+ // If there is a default value associated with this arg then add it to the
+ // b.buildArgs, later default values for the same arg override earlier ones.
+ // The args passed to builder (UserArgs) override the default value of 'arg'
+ // Don't add them here as they were already set in NewBuilder.
+ if _, ok := b.UserArgs[name]; !ok && hasDefault {
+ b.Args[name] = value
+ }
}
return nil
diff --git a/dispatchers_test.go b/dispatchers_test.go
index fb4c868..a40ed84 100644
--- a/dispatchers_test.go
+++ b/dispatchers_test.go
@@ -660,3 +660,26 @@ func TestDispatchRunFlags(t *testing.T) {
}
}
+
+func TestDispatchFromFlags(t *testing.T) {
+ expectedPlatform := "linux/arm64"
+ mybuilder := Builder{
+ RunConfig: docker.Config{
+ WorkingDir: "/root",
+ Cmd: []string{"/bin/sh"},
+ Image: "busybox",
+ },
+ }
+
+ flags := []string{"--platform=linux/arm64"}
+ args := []string{""}
+ original := "FROM --platform=linux/arm64 busybox"
+
+ if err := from(&mybuilder, args, nil, flags, original); err != nil {
+ t.Errorf("dispatchAdd error: %v", err)
+ }
+
+ if mybuilder.Platform != expectedPlatform {
+ t.Errorf("Expected %v, to match %v\n", expectedPlatform, mybuilder.Platform)
+ }
+}
diff --git a/dockerclient/archive.go b/dockerclient/archive.go
index 8e1096f..68672b9 100644
--- a/dockerclient/archive.go
+++ b/dockerclient/archive.go
@@ -3,6 +3,7 @@ package dockerclient
import (
"archive/tar"
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -16,14 +17,21 @@ import (
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/fileutils"
"github.com/containers/storage/pkg/idtools"
+ "github.com/containers/storage/pkg/ioutils"
"k8s.io/klog"
)
var isArchivePath = archive.IsArchivePath
+var dstNeedsToBeDirectoryError = errors.New("copying would overwrite content that was already copied; destination needs to be a directory")
// TransformFileFunc is given a chance to transform an arbitrary input file.
type TransformFileFunc func(h *tar.Header, r io.Reader) (data []byte, update bool, skip bool, err error)
+// FetchArchiveFunc retrieves an entire second copy of the archive we're
+// processing, so that we can fetch something from it that we discarded
+// earlier. This is expensive, so it is only called when it's needed.
+type FetchArchiveFunc func(pw *io.PipeWriter)
+
// FilterArchive transforms the provided input archive to a new archive,
// giving the fn a chance to transform arbitrary files.
func FilterArchive(r io.Reader, w io.Writer, fn TransformFileFunc) error {
@@ -42,7 +50,7 @@ func FilterArchive(r io.Reader, w io.Writer, fn TransformFileFunc) error {
var body io.Reader = tr
name := h.Name
data, ok, skip, err := fn(h, tr)
- klog.V(6).Infof("Transform %s -> %s: data=%t ok=%t skip=%t err=%v", name, h.Name, data != nil, ok, skip, err)
+ klog.V(6).Infof("Transform %s(0%o) -> %s: data=%t ok=%t skip=%t err=%v", name, h.Mode, h.Name, data != nil, ok, skip, err)
if err != nil {
return err
}
@@ -177,14 +185,100 @@ func archiveFromDisk(directory string, src, dst string, allowDownload bool, excl
directory = filepath.Dir(directory)
}
- options, err := archiveOptionsFor(infos, dst, excludes, check)
+ options, err := archiveOptionsFor(directory, infos, dst, excludes, check)
if err != nil {
return nil, nil, err
}
- klog.V(4).Infof("Tar of %s %#v", directory, options)
- rc, err := archive.TarWithOptions(directory, options)
- return rc, rc, err
+ pipeReader, pipeWriter := io.Pipe() // the archive we're creating
+
+ includeFiles := options.IncludeFiles
+ var returnedError error
+ go func() {
+ defer pipeWriter.Close()
+ tw := tar.NewWriter(pipeWriter)
+ defer tw.Close()
+ var nonArchives []string
+ for _, includeFile := range includeFiles {
+ if allowDownload && src != "." && src != "/" && isArchivePath(filepath.Join(directory, includeFile)) {
+ // it's an archive -> copy each item to the
+ // archive being written to the pipe writer
+ klog.V(4).Infof("Extracting %s", includeFile)
+ if err := func() error {
+ f, err := os.Open(filepath.Join(directory, includeFile))
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ dc, err := archive.DecompressStream(f)
+ if err != nil {
+ return err
+ }
+ defer dc.Close()
+ tr := tar.NewReader(dc)
+ hdr, err := tr.Next()
+ for err == nil {
+ if renamed, ok := options.RebaseNames[includeFile]; ok {
+ hdr.Name = strings.TrimSuffix(renamed, includeFile) + hdr.Name
+ if hdr.Typeflag == tar.TypeLink {
+ hdr.Linkname = strings.TrimSuffix(renamed, includeFile) + hdr.Linkname
+ }
+ }
+ tw.WriteHeader(hdr)
+ _, err = io.Copy(tw, tr)
+ if err != nil {
+ break
+ }
+ hdr, err = tr.Next()
+ }
+ if err != nil && err != io.EOF {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ returnedError = err
+ break
+ }
+ continue
+ }
+ nonArchives = append(nonArchives, includeFile)
+ }
+ if len(nonArchives) > 0 && returnedError == nil {
+ // the not-archive items -> add them all to the archive as-is
+ options.IncludeFiles = nonArchives
+ klog.V(4).Infof("Tar of %s %#v", directory, options)
+ rc, err := archive.TarWithOptions(directory, options)
+ if err != nil {
+ returnedError = err
+ return
+ }
+ defer rc.Close()
+ tr := tar.NewReader(rc)
+ hdr, err := tr.Next()
+ for err == nil {
+ tw.WriteHeader(hdr)
+ _, err = io.Copy(tw, tr)
+ if err != nil {
+ break
+ }
+ hdr, err = tr.Next()
+ }
+ if err != nil && err != io.EOF {
+ returnedError = err
+ return
+ }
+ }
+ }()
+
+ // the reader should close the pipe, and also get any error we need to report
+ readWrapper := ioutils.NewReadCloserWrapper(pipeReader, func() error {
+ if err := pipeReader.Close(); err != nil {
+ return err
+ }
+ return returnedError
+ })
+
+ return readWrapper, readWrapper, err
}
func archiveFromFile(file string, src, dst string, excludes []string, check DirectoryCheck) (io.Reader, io.Closer, error) {
@@ -196,7 +290,24 @@ func archiveFromFile(file string, src, dst string, excludes []string, check Dire
}
}
- mapper, _, err := newArchiveMapper(src, dst, excludes, true, check)
+ refetch := func(pw *io.PipeWriter) {
+ f, err := os.Open(file)
+ if err != nil {
+ pw.CloseWithError(err)
+ return
+ }
+ defer f.Close()
+ dc, err := archive.DecompressStream(f)
+ if err != nil {
+ pw.CloseWithError(err)
+ return
+ }
+ defer dc.Close()
+ _, err = io.Copy(pw, dc)
+ pw.CloseWithError(err)
+ }
+
+ mapper, _, err := newArchiveMapper(src, dst, excludes, false, true, check, refetch, true)
if err != nil {
return nil, nil, err
}
@@ -209,24 +320,24 @@ func archiveFromFile(file string, src, dst string, excludes []string, check Dire
r, err := transformArchive(f, true, mapper.Filter)
cc := newCloser(func() error {
err := f.Close()
- if !mapper.foundItems {
- return makeNotExistError(src)
+ if mapper.foundItems == 0 {
+ return fmt.Errorf("%s: %w", src, os.ErrNotExist)
}
return err
})
return r, cc, err
}
-func archiveFromContainer(in io.Reader, src, dst string, excludes []string, check DirectoryCheck) (io.ReadCloser, string, error) {
- mapper, archiveRoot, err := newArchiveMapper(src, dst, excludes, false, check)
+func archiveFromContainer(in io.Reader, src, dst string, excludes []string, check DirectoryCheck, refetch FetchArchiveFunc, assumeDstIsDirectory bool) (io.ReadCloser, string, error) {
+ mapper, archiveRoot, err := newArchiveMapper(src, dst, excludes, true, false, check, refetch, assumeDstIsDirectory)
if err != nil {
return nil, "", err
}
r, err := transformArchive(in, false, mapper.Filter)
rc := readCloser{Reader: r, Closer: newCloser(func() error {
- if !mapper.foundItems {
- return makeNotExistError(src)
+ if mapper.foundItems == 0 {
+ return fmt.Errorf("%s: %w", src, os.ErrNotExist)
}
return nil
})}
@@ -256,7 +367,7 @@ func transformArchive(r io.Reader, compressed bool, fn TransformFileFunc) (io.Re
// a (dir) -> test/
// a (file) -> test/
//
-func archivePathMapper(src, dst string, isDestDir bool) (fn func(name string, isDir bool) (string, bool)) {
+func archivePathMapper(src, dst string, isDestDir bool) (fn func(itemCount *int, name string, isDir bool) (string, bool, error)) {
srcPattern := filepath.Clean(src)
if srcPattern == "." {
srcPattern = "*"
@@ -267,33 +378,38 @@ func archivePathMapper(src, dst string, isDestDir bool) (fn func(name string, is
// no wildcards
if !containsWildcards(pattern) {
- return func(name string, isDir bool) (string, bool) {
+ return func(itemCount *int, name string, isDir bool) (string, bool, error) {
// when extracting from the working directory, Docker prefaces with ./
if strings.HasPrefix(name, "."+string(filepath.Separator)) {
name = name[2:]
}
if name == srcPattern {
- if isDir {
- return "", false
+ if isDir { // the source is a directory: this directory; skip it
+ return "", false, nil
+ }
+ if isDestDir { // the destination is a directory, put this under it
+ return filepath.Join(dst, filepath.Base(name)), true, nil
}
- if isDestDir {
- return filepath.Join(dst, filepath.Base(name)), true
+ // the source is a non-directory: copy to the destination's name
+ if itemCount != nil && *itemCount != 0 { // but we've already written something there
+ return "", false, dstNeedsToBeDirectoryError // tell the caller to start over
}
- return dst, true
+ return dst, true, nil
}
+ // source is a directory, this is under it; put this under the destination directory
remainder := strings.TrimPrefix(name, srcPattern+string(filepath.Separator))
if remainder == name {
- return "", false
+ return "", false, nil
}
- return filepath.Join(dst, remainder), true
+ return filepath.Join(dst, remainder), true, nil
}
}
// root with pattern
prefix := filepath.Dir(srcPattern)
if prefix == "." {
- return func(name string, isDir bool) (string, bool) {
+ return func(itemCount *int, name string, isDir bool) (string, bool, error) {
// match only on the first segment under the prefix
var firstSegment = name
if i := strings.Index(name, string(filepath.Separator)); i != -1 {
@@ -301,18 +417,24 @@ func archivePathMapper(src, dst string, isDestDir bool) (fn func(name string, is
}
ok, _ := filepath.Match(pattern, firstSegment)
if !ok {
- return "", false
+ return "", false, nil
}
- return filepath.Join(dst, name), true
+ if !isDestDir && !isDir { // the destination is not a directory, put this right there
+ if itemCount != nil && *itemCount != 0 { // but we've already written something there
+ return "", false, dstNeedsToBeDirectoryError // tell the caller to start over
+ }
+ return dst, true, nil
+ }
+ return filepath.Join(dst, name), true, nil
}
}
prefix += string(filepath.Separator)
// nested with pattern
- return func(name string, isDir bool) (string, bool) {
+ return func(_ *int, name string, isDir bool) (string, bool, error) {
remainder := strings.TrimPrefix(name, prefix)
if remainder == name {
- return "", false
+ return "", false, nil
}
// match only on the first segment under the prefix
var firstSegment = remainder
@@ -321,27 +443,31 @@ func archivePathMapper(src, dst string, isDestDir bool) (fn func(name string, is
}
ok, _ := filepath.Match(pattern, firstSegment)
if !ok {
- return "", false
+ return "", false, nil
}
- return filepath.Join(dst, remainder), true
+ return filepath.Join(dst, remainder), true, nil
}
}
type archiveMapper struct {
- exclude *fileutils.PatternMatcher
- rename func(name string, isDir bool) (string, bool)
- prefix string
- resetOwners bool
- foundItems bool
+ exclude *fileutils.PatternMatcher
+ rename func(itemCount *int, name string, isDir bool) (string, bool, error)
+ prefix string
+ dst string
+ resetDstMode bool
+ resetOwners bool
+ foundItems int
+ refetch FetchArchiveFunc
+ renameLinks map[string]string
}
-func newArchiveMapper(src, dst string, excludes []string, resetOwners bool, check DirectoryCheck) (*archiveMapper, string, error) {
+func newArchiveMapper(src, dst string, excludes []string, resetDstMode, resetOwners bool, check DirectoryCheck, refetch FetchArchiveFunc, assumeDstIsDirectory bool) (*archiveMapper, string, error) {
ex, err := fileutils.NewPatternMatcher(excludes)
if err != nil {
return nil, "", err
}
- isDestDir := strings.HasSuffix(dst, "/") || path.Base(dst) == "."
+ isDestDir := strings.HasSuffix(dst, "/") || path.Base(dst) == "." || strings.HasSuffix(src, "/") || path.Base(src) == "." || assumeDstIsDirectory
dst = path.Clean(dst)
if !isDestDir && check != nil {
isDir, err := check.IsDirectory(dst)
@@ -380,10 +506,14 @@ func newArchiveMapper(src, dst string, excludes []string, resetOwners bool, chec
mapperFn := archivePathMapper(srcPattern, dst, isDestDir)
return &archiveMapper{
- exclude: ex,
- rename: mapperFn,
- prefix: prefix,
- resetOwners: resetOwners,
+ exclude: ex,
+ rename: mapperFn,
+ prefix: prefix,
+ dst: dst,
+ resetDstMode: resetDstMode,
+ resetOwners: resetOwners,
+ refetch: refetch,
+ renameLinks: make(map[string]string),
}, archiveRoot, nil
}
@@ -401,7 +531,10 @@ func (m *archiveMapper) Filter(h *tar.Header, r io.Reader) ([]byte, bool, bool,
// skip a file if it doesn't match the src
isDir := h.Typeflag == tar.TypeDir
- newName, ok := m.rename(h.Name, isDir)
+ newName, ok, err := m.rename(&m.foundItems, h.Name, isDir)
+ if err != nil {
+ return nil, false, true, err
+ }
if !ok {
return nil, false, true, nil
}
@@ -413,33 +546,96 @@ func (m *archiveMapper) Filter(h *tar.Header, r io.Reader) ([]byte, bool, bool,
return nil, false, true, nil
}
- m.foundItems = true
+ m.foundItems++
h.Name = newName
+ if m.resetDstMode && isDir && path.Clean(h.Name) == path.Clean(m.dst) {
+ h.Mode = (h.Mode & ^0o777) | 0o755
+ }
+
if h.Typeflag == tar.TypeLink {
- // run the link target name through the same mapping the Name
- // in the target's entry would have gotten
- linkName := strings.TrimPrefix(h.Linkname, "/")
- if !strings.HasPrefix(linkName, m.prefix) {
- klog.V(6).Infof("No prefix %q in link target %q", m.prefix, h.Linkname)
- return nil, false, true, nil
- }
- linkName = strings.TrimPrefix(strings.TrimPrefix(linkName, m.prefix), "/")
- newTarget, ok := m.rename(linkName, false)
- if !ok {
- klog.V(6).Infof("Transform link target %s -> %s: ok=%t skip=%t", h.Linkname, newTarget, ok, true)
- return nil, false, true, nil
+ if newTarget, ok := m.renameLinks[h.Linkname]; ok {
+ // we already replaced the original link target, so make this a link to the file we copied
+ klog.V(6).Infof("Replaced link target %s -> %s: ok=%t", h.Linkname, newTarget, ok)
+ h.Linkname = newTarget
+ } else {
+ needReplacement := false
+ // run the link target name through the same mapping the Name
+ // in the target's entry would have gotten
+ linkName := strings.TrimPrefix(h.Linkname, "/")
+ if !strings.HasPrefix(linkName, m.prefix) {
+ // the link target didn't start with the prefix, so it wasn't passed along
+ needReplacement = true
+ }
+ var newTarget string
+ if !needReplacement {
+ linkName = strings.TrimPrefix(strings.TrimPrefix(linkName, m.prefix), "/")
+ var ok bool
+ if newTarget, ok, err = m.rename(nil, linkName, false); err != nil {
+ return nil, false, true, err
+ }
+ if !ok || newTarget == "." {
+ // the link target wasn't passed along
+ needReplacement = true
+ }
+ }
+ if !needReplacement {
+ if ok, _ := m.exclude.Matches(linkName); ok {
+ // link target was skipped based on excludes
+ needReplacement = true
+ }
+ }
+ if !needReplacement {
+ // the link target was passed along, everything's fine
+ klog.V(6).Infof("Transform link target %s -> %s: ok=%t skip=%t", h.Linkname, newTarget, ok, true)
+ h.Linkname = newTarget
+ } else {
+ // the link target wasn't passed along, splice it back in as this file
+ if m.refetch == nil {
+ return nil, false, true, fmt.Errorf("need to create %q as a hard link to %q, but did not copy %q", h.Name, h.Linkname, h.Linkname)
+ }
+ pr, pw := io.Pipe()
+ go m.refetch(pw)
+ tr2 := tar.NewReader(pr)
+ rehdr, err := tr2.Next()
+ for err == nil && rehdr.Name != h.Linkname {
+ rehdr, err = tr2.Next()
+ }
+ if err != nil {
+ pr.Close()
+ return nil, false, true, fmt.Errorf("needed to create %q as a hard link to %q, but got error refetching %q: %v", h.Name, h.Linkname, h.Linkname, err)
+ }
+ buf, err := ioutil.ReadAll(pr)
+ pr.Close()
+ if err != nil {
+ return nil, false, true, fmt.Errorf("needed to create %q as a hard link to %q, but got error refetching contents of %q: %v", h.Name, h.Linkname, h.Linkname, err)
+ }
+ m.renameLinks[h.Linkname] = h.Name
+ h.Typeflag = tar.TypeReg
+ h.Size, h.Mode = rehdr.Size, rehdr.Mode
+ h.Uid, h.Gid = rehdr.Uid, rehdr.Gid
+ h.Uname, h.Gname = rehdr.Uname, rehdr.Gname
+ h.ModTime, h.AccessTime, h.ChangeTime = rehdr.ModTime, rehdr.AccessTime, rehdr.ChangeTime
+ h.Xattrs = nil
+ for k, v := range rehdr.Xattrs {
+ if h.Xattrs != nil {
+ h.Xattrs = make(map[string]string)
+ }
+ h.Xattrs[k] = v
+ }
+ klog.V(6).Infof("Transform link %s -> reg %s", h.Linkname, h.Name)
+ h.Linkname = ""
+ return buf, true, false, nil
+ }
}
- klog.V(6).Infof("Transform link target %s -> %s: ok=%t", h.Linkname, newTarget, ok)
- h.Linkname = newTarget
}
// include all files
return nil, false, false, nil
}
-func archiveOptionsFor(infos []CopyInfo, dst string, excludes []string, check DirectoryCheck) (*archive.TarOptions, error) {
+func archiveOptionsFor(directory string, infos []CopyInfo, dst string, excludes []string, check DirectoryCheck) (*archive.TarOptions, error) {
dst = trimLeadingPath(dst)
dstIsDir := strings.HasSuffix(dst, "/") || dst == "." || dst == "/" || strings.HasSuffix(dst, "/.")
dst = trimTrailingSlash(dst)
@@ -462,6 +658,22 @@ func archiveOptionsFor(infos []CopyInfo, dst string, excludes []string, check Di
return options, nil
}
+ if !dstIsDir {
+ for _, info := range infos {
+ if ok, _ := pm.Matches(info.Path); ok {
+ continue
+ }
+ infoPath := info.Path
+ if directory != "" {
+ infoPath = filepath.Join(directory, infoPath)
+ }
+ if isArchivePath(infoPath) {
+ dstIsDir = true
+ break
+ }
+ }
+ }
+
for _, info := range infos {
if ok, _ := pm.Matches(info.Path); ok {
continue
diff --git a/dockerclient/archive_112.go b/dockerclient/archive_112.go
deleted file mode 100644
index 715364d..0000000
--- a/dockerclient/archive_112.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build !go1.13
-
-package dockerclient
-
-import (
- "os"
-)
-
-func makeNotExistError(s string) error {
- return os.ErrNotExist
-}
diff --git a/dockerclient/archive_113.go b/dockerclient/archive_113.go
deleted file mode 100644
index 1c0f5cc..0000000
--- a/dockerclient/archive_113.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build go1.13
-
-package dockerclient
-
-import (
- "fmt"
- "os"
-)
-
-func makeNotExistError(s string) error {
- return fmt.Errorf("%w: %s", os.ErrNotExist, s)
-}
diff --git a/dockerclient/archive_test.go b/dockerclient/archive_test.go
index aae3ed6..d63625d 100644
--- a/dockerclient/archive_test.go
+++ b/dockerclient/archive_test.go
@@ -37,8 +37,33 @@ func newArchiveGenerator() *archiveGenerator {
return &archiveGenerator{}
}
+func typeflagAsString(b byte) string {
+ switch b {
+ case tar.TypeDir:
+ return "dir"
+ case tar.TypeReg:
+ return "reg"
+ case tar.TypeRegA:
+ return "rega"
+ default:
+ return fmt.Sprintf("%d", b)
+ }
+}
+
+func (g *archiveGenerator) String() string {
+ s := "["
+ for i := range g.Headers {
+ if i > 0 {
+ s += ", "
+ }
+ s += fmt.Sprintf("{%q: %v}", g.Headers[i].Name, typeflagAsString(g.Headers[i].Typeflag))
+ }
+ s += "]"
+ return s
+}
+
func (g *archiveGenerator) File(name string) *archiveGenerator {
- g.Headers = append(g.Headers, &tar.Header{Name: name, Size: 1})
+ g.Headers = append(g.Headers, &tar.Header{Name: name, Typeflag: tar.TypeReg, Size: 1})
return g
}
@@ -313,10 +338,11 @@ func Test_archiveFromContainer(t *testing.T) {
check map[string]bool
}{
{
- gen: newArchiveGenerator().File("file").Dir("test").File("test/file2"),
- src: "/*",
- dst: "test",
- path: "/",
+ gen: newArchiveGenerator().File("file").Dir("test").File("test/file2"),
+ src: "/*",
+ dst: "test",
+ check: map[string]bool{"test": true},
+ path: "/",
expect: []string{
"test/file",
"test/test",
@@ -390,10 +416,11 @@ func Test_archiveFromContainer(t *testing.T) {
},
},
{
- gen: newArchiveGenerator().File("/b/file").Dir("/b/test").File("/b/test/file2"),
- src: "/a/b/*",
- dst: "/b",
- path: "/a/b",
+ gen: newArchiveGenerator().File("/b/file").Dir("/b/test").File("/b/test/file2"),
+ src: "/a/b/*",
+ dst: "/b",
+ check: map[string]bool{"/b": true},
+ path: "/a/b",
expect: []string{
"/b/file",
"/b/test",
@@ -487,12 +514,17 @@ func Test_archiveFromContainer(t *testing.T) {
testCase.dst,
testCase.excludes,
testDirectoryCheck(testCase.check),
+ func(pw *io.PipeWriter) {
+ _, err := io.Copy(pw, testCase.gen.Reader())
+ pw.CloseWithError(err)
+ },
+ false,
)
if err != nil {
t.Fatal(err)
}
if filepath.Clean(path) != testCase.path {
- t.Errorf("unexpected path: %s != %s", filepath.Clean(path), testCase.path)
+ t.Errorf("unexpected path for root of archive: %q != expected value %q", filepath.Clean(path), testCase.path)
}
tr := tar.NewReader(rc)
var found []string
@@ -512,7 +544,7 @@ func Test_archiveFromContainer(t *testing.T) {
}
sort.Strings(found)
if !reflect.DeepEqual(testCase.expect, found) {
- t.Errorf("unexpected files:\n%v\n%v", testCase.expect, found)
+ t.Errorf("from %q to %q with content: %v\nunexpected files:\nexpected: %v\nfound: %v", testCase.src, testCase.dst, testCase.gen, testCase.expect, found)
}
})
}
diff --git a/dockerclient/client.go b/dockerclient/client.go
index 803ec71..2d8931c 100644
--- a/dockerclient/client.go
+++ b/dockerclient/client.go
@@ -6,13 +6,14 @@ import (
"bytes"
"context"
"crypto/rand"
+ "errors"
"fmt"
"io"
"io/ioutil"
"os"
- "path"
"path/filepath"
"runtime"
+ "sort"
"strconv"
"strings"
@@ -98,6 +99,9 @@ type ClientExecutor struct {
// as a base for this build. Otherwise the FROM value from the
// Dockerfile is read (will be pulled if not locally present).
Image *docker.Image
+ // Committed is optional and is used to track a temporary image, if one
+ // was created, that was based on the container as its stage ended.
+ Committed *docker.Image
// AuthFn will handle authenticating any docker pulls if Image
// is set to nil.
@@ -108,7 +112,7 @@ type ClientExecutor struct {
LogFn func(format string, args ...interface{})
// Deferred is a list of operations that must be cleaned up at
- // the end of execution. Use Release() to handle these.
+ // the end of execution. Use Release() to invoke all of these.
Deferred []func() error
// Volumes handles saving and restoring volumes after RUN
@@ -116,7 +120,7 @@ type ClientExecutor struct {
Volumes *ContainerVolumeTracker
}
-// NotAuthFn can be used for AuthFn when no authentication is required in Docker.
+// NoAuthFn can be used for AuthFn when no authentication is required in Docker.
func NoAuthFn(string) ([]dockertypes.AuthConfig, bool) {
return nil, false
}
@@ -131,6 +135,9 @@ func NewClientExecutor(client *docker.Client) *ClientExecutor {
}
}
+// DefaultExcludes reads the default list of excluded file patterns from the
+// context directory's .containerignore file if it exists, or from the context
+// directory's .dockerignore file, if it exists.
func (e *ClientExecutor) DefaultExcludes() error {
var err error
e.Excludes, err = imagebuilder.ParseDockerignore(e.Directory)
@@ -138,21 +145,22 @@ func (e *ClientExecutor) DefaultExcludes() error {
}
// WithName creates a new child executor that will be used whenever a COPY statement
-// uses --from=NAME.
-func (e *ClientExecutor) WithName(name string) *ClientExecutor {
+// uses --from=NAME or --from=POSITION.
+func (e *ClientExecutor) WithName(name string, position int) *ClientExecutor {
if e.Named == nil {
e.Named = make(map[string]*ClientExecutor)
- e.Deferred = append([]func() error{func() error {
- var errs []error
- for _, named := range e.Named {
- errs = append(errs, named.Release()...)
- }
- if len(errs) > 0 {
- return fmt.Errorf("%v", errs)
- }
- return nil
- }}, e.Deferred...)
}
+ e.Deferred = append([]func() error{func() error {
+ stage, ok := e.Named[strconv.Itoa(position)]
+ if !ok {
+ return fmt.Errorf("error finding stage %d", position)
+ }
+ errs := stage.Release()
+ if len(errs) > 0 {
+ return fmt.Errorf("%v", errs)
+ }
+ return nil
+ }}, e.Deferred...)
copied := *e
copied.Name = name
@@ -160,9 +168,11 @@ func (e *ClientExecutor) WithName(name string) *ClientExecutor {
copied.Deferred = nil
copied.Image = nil
copied.Volumes = nil
+ copied.Committed = nil
child := &copied
e.Named[name] = child
+ e.Named[strconv.Itoa(position)] = child
return child
}
@@ -171,7 +181,7 @@ func (e *ClientExecutor) WithName(name string) *ClientExecutor {
func (e *ClientExecutor) Stages(b *imagebuilder.Builder, stages imagebuilder.Stages, from string) (*ClientExecutor, error) {
var stageExecutor *ClientExecutor
for i, stage := range stages {
- stageExecutor = e.WithName(stage.Name)
+ stageExecutor = e.WithName(stage.Name, stage.Position)
var stageFrom string
if i == 0 {
@@ -186,11 +196,34 @@ func (e *ClientExecutor) Stages(b *imagebuilder.Builder, stages imagebuilder.Sta
if !ok {
return nil, fmt.Errorf("error: Unable to find stage %s builder", from)
}
- stageExecutor.Image = &docker.Image{
- Config: b.Builder.Config(),
+ if prereq.Committed == nil {
+ config := b.Builder.Config()
+ if prereq.Container.State.Running {
+ klog.V(4).Infof("Stopping container %s ...", prereq.Container.ID)
+ if err := e.Client.StopContainer(prereq.Container.ID, 0); err != nil {
+ return nil, fmt.Errorf("unable to stop build container: %v", err)
+ }
+ prereq.Container.State.Running = false
+ // Starting the container may perform escaping of args, so to be consistent
+ // we also set that here
+ config.ArgsEscaped = true
+ }
+ image, err := e.Client.CommitContainer(docker.CommitContainerOptions{
+ Container: prereq.Container.ID,
+ Run: config,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("unable to commit stage %s container: %v", from, err)
+ }
+ klog.V(4).Infof("Committed %s to %s as basis for image %q: %#v", prereq.Container.ID, image.ID, from, config)
+ // deleting this image will fail with an "image has dependent child images" error
+ // if it ends up being an ancestor of the final image, so don't bother returning
+ // errors from this specific removeImage() call
+ prereq.Deferred = append([]func() error{func() error { e.removeImage(image.ID); return nil }}, prereq.Deferred...)
+ prereq.Committed = image
}
- stageExecutor.Container = prereq.Container
- klog.V(4).Infof("Using previous stage %s as image: %#v", from, stageExecutor.Image.Config)
+ klog.V(4).Infof("Using image %s based on previous stage %s as image", prereq.Committed.ID, from)
+ from = prereq.Committed.ID
}
stageFrom = from
}
@@ -213,7 +246,7 @@ func (e *ClientExecutor) Stages(b *imagebuilder.Builder, stages imagebuilder.Sta
// provided Docker client. It will load the image if not specified,
// create a container if one does not already exist, and start a
// container if the Dockerfile contains RUN commands. It will cleanup
-// any containers it creates directly, and set the e.Image.ID field
+// any containers it creates directly, and set the e.Committed.ID field
// to the generated image.
func (e *ClientExecutor) Build(b *imagebuilder.Builder, node *parser.Node, from string) error {
defer e.Release()
@@ -247,10 +280,10 @@ func (e *ClientExecutor) Prepare(b *imagebuilder.Builder, node *parser.Node, fro
if err != nil {
return fmt.Errorf("unable to create a scratch image for this build: %v", err)
}
- e.Deferred = append(e.Deferred, func() error { return e.Client.RemoveImage(from) })
+ e.Deferred = append([]func() error{func() error { return e.removeImage(from) }}, e.Deferred...)
}
klog.V(4).Infof("Retrieving image %q", from)
- e.Image, err = e.LoadImage(from)
+ e.Image, err = e.LoadImageWithPlatform(from, b.Platform)
if err != nil {
return err
}
@@ -304,7 +337,7 @@ func (e *ClientExecutor) Prepare(b *imagebuilder.Builder, node *parser.Node, fro
if err != nil {
return fmt.Errorf("unable to create volume to mount secrets: %v", err)
}
- e.Deferred = append(e.Deferred, func() error { return e.Client.RemoveVolume(volumeName) })
+ e.Deferred = append([]func() error{func() error { return e.Client.RemoveVolume(volumeName) }}, e.Deferred...)
sharedMount = v.Mountpoint
opts.HostConfig.Binds = append(opts.HostConfig.Binds, volumeName+":"+e.ContainerTransientMount)
}
@@ -426,7 +459,7 @@ func (e *ClientExecutor) Commit(b *imagebuilder.Builder) error {
return fmt.Errorf("unable to commit build container: %v", err)
}
- e.Image = image
+ e.Committed = image
klog.V(4).Infof("Committed %s to %s", e.Container.ID, image.ID)
if len(e.Tag) > 0 {
@@ -437,7 +470,7 @@ func (e *ClientExecutor) Commit(b *imagebuilder.Builder) error {
Tag: tag,
})
if err != nil {
- e.Deferred = append(e.Deferred, func() error { return e.Client.RemoveImageExtended(image.ID, docker.RemoveImageOptions{Force: true}) })
+ e.Deferred = append([]func() error{func() error { return e.removeImage(image.ID) }}, e.Deferred...)
return fmt.Errorf("unable to tag %q: %v", s, err)
}
e.LogFn("Tagged as %s", s)
@@ -498,7 +531,17 @@ func (e *ClientExecutor) removeContainer(id string) error {
Force: true,
})
if _, ok := err.(*docker.NoSuchContainer); err != nil && !ok {
- return fmt.Errorf("unable to cleanup container: %v", err)
+ return fmt.Errorf("unable to cleanup container %s: %v", id, err)
+ }
+ return nil
+}
+
+// removeImage removes the provided image ID
+func (e *ClientExecutor) removeImage(id string) error {
+ if err := e.Client.RemoveImageExtended(id, docker.RemoveImageOptions{
+ Force: true,
+ }); err != nil {
+ return fmt.Errorf("unable to clean up image %s: %v", id, err)
}
return nil
}
@@ -546,6 +589,12 @@ func randSeq(source string, n int) (string, error) {
// LoadImage checks the client for an image matching from. If not found,
// attempts to pull the image and then tries to inspect again.
func (e *ClientExecutor) LoadImage(from string) (*docker.Image, error) {
+ return e.LoadImageWithPlatform(from, "")
+}
+
+// LoadImage checks the client for an image matching from. If not found,
+// attempts to pull the image with specified platform string.
+func (e *ClientExecutor) LoadImageWithPlatform(from string, platform string) (*docker.Image, error) {
image, err := e.Client.InspectImage(from)
if err == nil {
return image, nil
@@ -596,6 +645,7 @@ func (e *ClientExecutor) LoadImage(from string) (*docker.Image, error) {
Repository: repository,
Tag: tag,
OutputStream: pullWriter,
+ Platform: platform,
RawJSONStream: true,
}
if klog.V(5) {
@@ -632,6 +682,26 @@ func (e *ClientExecutor) Preserve(path string) error {
}
func (e *ClientExecutor) EnsureContainerPath(path string) error {
+ return e.createOrReplaceContainerPathWithOwner(path, 0, 0, nil)
+}
+
+func (e *ClientExecutor) EnsureContainerPathAs(path, user string, mode *os.FileMode) error {
+ uid, gid := 0, 0
+
+ u, g, err := e.getUser(user)
+ if err == nil {
+ uid = u
+ gid = g
+ }
+
+ return e.createOrReplaceContainerPathWithOwner(path, uid, gid, mode)
+}
+
+func (e *ClientExecutor) createOrReplaceContainerPathWithOwner(path string, uid, gid int, mode *os.FileMode) error {
+ if mode == nil {
+ m := os.FileMode(0755)
+ mode = &m
+ }
createPath := func(dest string) error {
var writerErr error
if !strings.HasSuffix(dest, "/") {
@@ -650,7 +720,9 @@ func (e *ClientExecutor) EnsureContainerPath(path string) error {
writerErr = tarball.WriteHeader(&tar.Header{
Name: dest,
Typeflag: tar.TypeDir,
- Mode: 0755,
+ Mode: int64(*mode),
+ Uid: uid,
+ Gid: gid,
})
}()
klog.V(4).Infof("Uploading empty archive to %q", dest)
@@ -792,18 +864,22 @@ func (e *ClientExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) er
return e.CopyContainer(e.Container, excludes, copies...)
}
-// CopyContainer copies the provided content into a destination container.
-func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []string, copies ...imagebuilder.Copy) error {
- chownUid, chownGid := -1, -1
- chown := func(h *tar.Header, r io.Reader) (data []byte, update bool, skip bool, err error) {
- if chownUid != -1 {
- h.Uid = chownUid
+func (e *ClientExecutor) findMissingParents(container *docker.Container, dest string) (parents []string, err error) {
+ destParent := filepath.Clean(dest)
+ for filepath.Dir(destParent) != destParent {
+ exists, err := isContainerPathDirectory(e.Client, container.ID, destParent)
+ if err != nil {
+ return nil, err
}
- if chownGid != -1 {
- h.Gid = chownGid
+ if !exists {
+ parents = append(parents, destParent)
}
- return nil, false, false, nil
+ destParent = filepath.Dir(destParent)
}
+ return parents, nil
+}
+
+func (e *ClientExecutor) getUser(userspec string) (int, int, error) {
readFile := func(path string) ([]byte, error) {
var buffer, contents bytes.Buffer
if err := e.Client.DownloadFromContainer(e.Container.ID, docker.DownloadFromContainerOptions{
@@ -832,7 +908,7 @@ func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []s
return nil, fmt.Errorf("size mismatch reading contents of %q: %v", path, err)
}
hdr, err = tr.Next()
- if err != nil && !errorIsEOF(err) {
+ if err != nil && !errors.Is(err, io.EOF) {
return nil, fmt.Errorf("error reading archive of %q: %v", path, err)
}
if err == nil {
@@ -863,75 +939,96 @@ func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []s
}
return *value, nil
}
+
+ spec := strings.SplitN(userspec, ":", 2)
+ if len(spec) == 2 {
+ parsedUid, err := strconv.ParseUint(spec[0], 10, 32)
+ if err != nil {
+ // maybe it's a user name? look up the UID
+ passwdFile, err := readFile("/etc/passwd")
+ if err != nil {
+ return -1, -1, err
+ }
+ uid, err := parse(passwdFile, 0, spec[0], 7, 2)
+ if err != nil {
+ return -1, -1, fmt.Errorf("error reading UID value from passwd file for --chown=%s: %v", spec[0], err)
+ }
+ parsedUid, err = strconv.ParseUint(uid, 10, 32)
+ if err != nil {
+ return -1, -1, fmt.Errorf("error parsing UID value %q from passwd file for --chown=%s", uid, userspec)
+ }
+ }
+ parsedGid, err := strconv.ParseUint(spec[1], 10, 32)
+ if err != nil {
+ // maybe it's a group name? look up the GID
+ groupFile, err := readFile("/etc/group")
+ if err != nil {
+ return -1, -1, err
+ }
+ gid, err := parse(groupFile, 0, spec[1], 4, 2)
+ if err != nil {
+ return -1, -1, err
+ }
+ parsedGid, err = strconv.ParseUint(gid, 10, 32)
+ if err != nil {
+ return -1, -1, fmt.Errorf("error parsing GID value %q from group file for --chown=%s", gid, userspec)
+ }
+ }
+ return int(parsedUid), int(parsedGid), nil
+ }
+
+ var parsedUid, parsedGid uint64
+ if id, err := strconv.ParseUint(spec[0], 10, 32); err == nil {
+ // it's an ID. use it as both the UID and the GID
+ parsedUid = id
+ parsedGid = id
+ } else {
+ // it's a user name, we'll need to look up their UID and primary GID
+ passwdFile, err := readFile("/etc/passwd")
+ if err != nil {
+ return -1, -1, err
+ }
+ // read the UID and primary GID
+ uid, err := parse(passwdFile, 0, spec[0], 7, 2)
+ if err != nil {
+ return -1, -1, fmt.Errorf("error reading UID value from /etc/passwd for --chown=%s", userspec)
+ }
+ gid, err := parse(passwdFile, 0, spec[0], 7, 3)
+ if err != nil {
+ return -1, -1, fmt.Errorf("error reading GID value from /etc/passwd for --chown=%s", userspec)
+ }
+ if parsedUid, err = strconv.ParseUint(uid, 10, 32); err != nil {
+ return -1, -1, fmt.Errorf("error parsing UID value %q from /etc/passwd for --chown=%s", uid, userspec)
+ }
+ if parsedGid, err = strconv.ParseUint(gid, 10, 32); err != nil {
+ return -1, -1, fmt.Errorf("error parsing GID value %q from /etc/passwd for --chown=%s", gid, userspec)
+ }
+ }
+ return int(parsedUid), int(parsedGid), nil
+}
+
+// CopyContainer copies the provided content into a destination container.
+func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []string, copies ...imagebuilder.Copy) error {
+ chownUid, chownGid := -1, -1
+ chown := func(h *tar.Header, r io.Reader) (data []byte, update bool, skip bool, err error) {
+ if chownUid != -1 {
+ h.Uid = chownUid
+ }
+ if chownGid != -1 {
+ h.Gid = chownGid
+ }
+ if (h.Uid > 0x1fffff || h.Gid > 0x1fffff) && h.Format == tar.FormatUSTAR {
+ h.Format = tar.FormatPAX
+ }
+ return nil, false, false, nil
+ }
for _, c := range copies {
chownUid, chownGid = -1, -1
if c.Chown != "" {
- spec := strings.SplitN(c.Chown, ":", 2)
- if len(spec) == 2 {
- parsedUid, err := strconv.ParseUint(spec[0], 10, 32)
- if err != nil {
- // maybe it's a user name? look up the UID
- passwdFile, err := readFile("/etc/passwd")
- if err != nil {
- return err
- }
- uid, err := parse(passwdFile, 0, spec[0], 7, 2)
- if err != nil {
- return fmt.Errorf("error reading UID value from passwd file for --chown=%s: %v", spec[0], err)
- }
- parsedUid, err = strconv.ParseUint(uid, 10, 32)
- if err != nil {
- return fmt.Errorf("error parsing UID value %q from passwd file for --chown=%s", uid, c.Chown)
- }
- }
- parsedGid, err := strconv.ParseUint(spec[1], 10, 32)
- if err != nil {
- // maybe it's a group name? look up the GID
- groupFile, err := readFile("/etc/group")
- if err != nil {
- return err
- }
- gid, err := parse(groupFile, 0, spec[1], 4, 2)
- if err != nil {
- return err
- }
- parsedGid, err = strconv.ParseUint(gid, 10, 32)
- if err != nil {
- return fmt.Errorf("error parsing GID value %q from group file for --chown=%s", gid, c.Chown)
- }
- }
- chownUid = int(parsedUid)
- chownGid = int(parsedGid)
- } else {
- var parsedUid, parsedGid uint64
- if id, err := strconv.ParseUint(spec[0], 10, 32); err == nil {
- // it's an ID. use it as both the UID and the GID
- parsedUid = id
- parsedGid = id
- } else {
- // it's a user name, we'll need to look up their UID and primary GID
- passwdFile, err := readFile("/etc/passwd")
- if err != nil {
- return err
- }
- // read the UID and primary GID
- uid, err := parse(passwdFile, 0, spec[0], 7, 2)
- if err != nil {
- return fmt.Errorf("error reading UID value from /etc/passwd for --chown=%s", c.Chown)
- }
- gid, err := parse(passwdFile, 0, spec[0], 7, 3)
- if err != nil {
- return fmt.Errorf("error reading GID value from /etc/passwd for --chown=%s", c.Chown)
- }
- if parsedUid, err = strconv.ParseUint(uid, 10, 32); err != nil {
- return fmt.Errorf("error parsing UID value %q from /etc/passwd for --chown=%s", uid, c.Chown)
- }
- if parsedGid, err = strconv.ParseUint(gid, 10, 32); err != nil {
- return fmt.Errorf("error parsing GID value %q from /etc/passwd for --chown=%s", gid, c.Chown)
- }
- }
- chownUid = int(parsedUid)
- chownGid = int(parsedGid)
+ var err error
+ chownUid, chownGid, err = e.getUser(c.Chown)
+ if err != nil {
+ return err
}
}
// TODO: reuse source
@@ -939,12 +1036,20 @@ func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []s
if src == "" {
src = "*"
}
+ assumeDstIsDirectory := len(c.Src) > 1
+ repeatThisSrc:
klog.V(4).Infof("Archiving %s download=%t fromFS=%t from=%s", src, c.Download, c.FromFS, c.From)
var r io.Reader
var closer io.Closer
var err error
if len(c.From) > 0 {
- r, closer, err = e.archiveFromContainer(c.From, src, c.Dest)
+ if !assumeDstIsDirectory {
+ var err error
+ if assumeDstIsDirectory, err = e.isContainerGlobMultiple(e.Client, c.From, src); err != nil {
+ return err
+ }
+ }
+ r, closer, err = e.archiveFromContainer(c.From, src, c.Dest, assumeDstIsDirectory)
} else {
r, closer, err = e.Archive(c.FromFS, src, c.Dest, c.Download, excludes)
}
@@ -953,17 +1058,41 @@ func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []s
}
asOwner := ""
if c.Chown != "" {
+ asOwner = fmt.Sprintf(" as %d:%d", chownUid, chownGid)
+ // the daemon would implicitly create missing
+ // directories with the wrong ownership, so
+ // check for any that don't exist and create
+ // them ourselves
+ missingParents, err := e.findMissingParents(container, c.Dest)
+ if err != nil {
+ return err
+ }
+ if len(missingParents) > 0 {
+ sort.Strings(missingParents)
+ klog.V(5).Infof("Uploading directories %v to %s%s", missingParents, container.ID, asOwner)
+ for _, missingParent := range missingParents {
+ if err := e.createOrReplaceContainerPathWithOwner(missingParent, chownUid, chownGid, nil); err != nil {
+ return err
+ }
+ }
+ }
filtered, err := transformArchive(r, false, chown)
if err != nil {
return err
}
r = filtered
- asOwner = fmt.Sprintf(" as %d:%d", chownUid, chownGid)
}
klog.V(5).Infof("Uploading to %s%s at %s", container.ID, asOwner, c.Dest)
if klog.V(6) {
logArchiveOutput(r, "Archive file for %s")
}
+ // add a workaround allow us to notice if a
+ // dstNeedsToBeDirectoryError was returned while
+ // attempting to read the data we're uploading,
+ // indicating that we thought the content would be just
+ // one item, but it actually isn't
+ reader := &readErrorWrapper{Reader: r}
+ r = reader
err = e.Client.UploadToContainer(container.ID, docker.UploadToContainerOptions{
InputStream: r,
Path: "/",
@@ -972,6 +1101,13 @@ func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []s
klog.Errorf("Error while closing stream container copy stream %s: %v", container.ID, err)
}
if err != nil {
+ if errors.Is(reader.err, dstNeedsToBeDirectoryError) && !assumeDstIsDirectory {
+ assumeDstIsDirectory = true
+ goto repeatThisSrc
+ }
+ if apiErr, ok := err.(*docker.Error); ok && apiErr.Status == 404 {
+ klog.V(4).Infof("path %s did not exist in container %s: %v", src, container.ID, err)
+ }
return err
}
}
@@ -979,6 +1115,16 @@ func (e *ClientExecutor) CopyContainer(container *docker.Container, excludes []s
return nil
}
+type readErrorWrapper struct {
+ io.Reader
+ err error
+}
+
+func (r *readErrorWrapper) Read(p []byte) (n int, err error) {
+ n, r.err = r.Reader.Read(p)
+ return n, r.err
+}
+
type closers []func() error
func (c closers) Close() error {
@@ -991,16 +1137,14 @@ func (c closers) Close() error {
return lastErr
}
-func (e *ClientExecutor) archiveFromContainer(from string, src, dst string) (io.Reader, io.Closer, error) {
+func (e *ClientExecutor) archiveFromContainer(from string, src, dst string, multipleSources bool) (io.Reader, io.Closer, error) {
var containerID string
- var containerConfig *docker.Config
if other, ok := e.Named[from]; ok {
if other.Container == nil {
return nil, nil, fmt.Errorf("the stage %q has not been built yet", from)
}
klog.V(5).Infof("Using container %s as input for archive request", other.Container.ID)
containerID = other.Container.ID
- containerConfig = other.Container.Config
} else {
klog.V(5).Infof("Creating a container temporarily for image input from %q in %s", from, src)
_, err := e.LoadImage(from)
@@ -1016,17 +1160,21 @@ func (e *ClientExecutor) archiveFromContainer(from string, src, dst string) (io.
return nil, nil, err
}
containerID = c.ID
- containerConfig = c.Config
e.Deferred = append([]func() error{func() error { return e.removeContainer(containerID) }}, e.Deferred...)
}
- if !strings.HasPrefix(src, "/") {
- src = path.Join(containerConfig.WorkingDir, src)
- }
-
check := newDirectoryCheck(e.Client, e.Container.ID)
pr, pw := io.Pipe()
- ar, archiveRoot, err := archiveFromContainer(pr, src, dst, nil, check)
+ var archiveRoot string
+ fetch := func(pw *io.PipeWriter) {
+ klog.V(6).Infof("Download from container %s at path %s", containerID, archiveRoot)
+ err := e.Client.DownloadFromContainer(containerID, docker.DownloadFromContainerOptions{
+ OutputStream: pw,
+ Path: archiveRoot,
+ })
+ pw.CloseWithError(err)
+ }
+ ar, archiveRoot, err := archiveFromContainer(pr, src, dst, nil, check, fetch, multipleSources)
if err != nil {
pr.Close()
pw.Close()
@@ -1040,15 +1188,53 @@ func (e *ClientExecutor) archiveFromContainer(from string, src, dst string) (io.
}
return err2
})
+ go fetch(pw)
+ return &readCloser{Reader: ar, Closer: closer}, pr, nil
+}
+
+func (e *ClientExecutor) isContainerGlobMultiple(client *docker.Client, from, glob string) (bool, error) {
+ reader, closer, err := e.archiveFromContainer(from, glob, "/ignored", true)
+ if err != nil {
+ return false, nil
+ }
+
+ defer closer.Close()
+ tr := tar.NewReader(reader)
+
+ h, err := tr.Next()
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ } else {
+ if apiErr, ok := err.(*docker.Error); ok && apiErr.Status == 404 {
+ klog.V(4).Infof("path %s did not exist in container %s: %v", glob, e.Container.ID, err)
+ err = nil
+ }
+ }
+ return false, err
+ }
+
+ klog.V(4).Infof("Retrieved first header from %s using glob %s: %#v", from, glob, h)
+
+ h, err = tr.Next()
+ if err != nil {
+ if err == io.EOF {
+ err = nil
+ }
+ return false, err
+ }
+
+ klog.V(4).Infof("Retrieved second header from %s using glob %s: %#v", from, glob, h)
+
+ // take the remainder of the input and discard it
go func() {
- klog.V(6).Infof("Download from container %s at path %s", containerID, archiveRoot)
- err := e.Client.DownloadFromContainer(containerID, docker.DownloadFromContainerOptions{
- OutputStream: pw,
- Path: archiveRoot,
- })
- pw.CloseWithError(err)
+ n, err := io.Copy(ioutil.Discard, reader)
+ if n > 0 || err != nil {
+ klog.V(6).Infof("Discarded %d bytes from end of from glob check, and got error: %v", n, err)
+ }
}()
- return &readCloser{Reader: ar, Closer: closer}, pr, nil
+
+ return true, nil
}
func (e *ClientExecutor) Archive(fromFS bool, src, dst string, allowDownload bool, excludes []string) (io.Reader, io.Closer, error) {
@@ -1073,28 +1259,6 @@ func (e *ClientExecutor) Archive(fromFS bool, src, dst string, allowDownload boo
klog.V(5).Infof("Archiving %s %s -> %s from context archive", e.ContextArchive, src, dst)
return archiveFromFile(e.ContextArchive, src, dst, excludes, check)
}
- // if the source is an archive, extract it under the destination directory
- srcFullPath := filepath.Join(e.Directory, src)
- if allowDownload && isArchivePath(srcFullPath) {
- f, err := os.Open(srcFullPath)
- if err != nil {
- return nil, nil, fmt.Errorf("error opening %q: %v", srcFullPath, err)
- }
- klog.V(5).Infof("Extracting %s -> %s from local archive", srcFullPath, dst)
- transform := func(h *tar.Header, r io.Reader) (data []byte, update bool, skip bool, err error) {
- h.Name = filepath.Join(dst, h.Name)
- if h.Typeflag == tar.TypeLink {
- h.Linkname = filepath.Join(dst, h.Linkname)
- }
- return nil, false, false, nil
- }
- filtered, err := transformArchive(f, true, transform)
- if err != nil {
- f.Close()
- return nil, nil, fmt.Errorf("error transforming archive %q: %v", srcFullPath, err)
- }
- return filtered, f, nil
- }
// if the context is a directory, we only allow relative includes
klog.V(5).Infof("Archiving %q %q -> %q from disk", e.Directory, src, dst)
return archiveFromDisk(e.Directory, src, dst, allowDownload, excludes, check)
@@ -1234,7 +1398,7 @@ func snapshotPath(path, containerID, tempDir string, client *docker.Client) (str
}
return len(h.Name) > 0
})
- if err == nil || errorIsEOF(err) {
+ if err == nil || errors.Is(err, io.EOF) {
tw.Flush()
w.Close()
klog.V(5).Infof("Snapshot rewritten from %s", path)
diff --git a/dockerclient/client_112.go b/dockerclient/client_112.go
deleted file mode 100644
index 60848f8..0000000
--- a/dockerclient/client_112.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build !go1.13
-
-package dockerclient
-
-import (
- "io"
-)
-
-func errorIsEOF(err error) bool {
- return err == io.EOF
-}
diff --git a/dockerclient/client_113.go b/dockerclient/client_113.go
deleted file mode 100644
index aa6a150..0000000
--- a/dockerclient/client_113.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build go1.13
-
-package dockerclient
-
-import (
- "errors"
- "io"
-)
-
-func errorIsEOF(err error) bool {
- return errors.Is(err, io.EOF)
-}
diff --git a/dockerclient/conformance_test.go b/dockerclient/conformance_test.go
index 3b61881..66508f3 100644
--- a/dockerclient/conformance_test.go
+++ b/dockerclient/conformance_test.go
@@ -16,7 +16,9 @@ import (
"path/filepath"
"reflect"
"regexp"
+ "strconv"
"strings"
+ "syscall"
"testing"
"time"
@@ -56,7 +58,11 @@ func TestMount(t *testing.T) {
}
e := NewClientExecutor(c)
- defer e.Release()
+ defer func() {
+ for _, err := range e.Release() {
+ t.Errorf("%v", err)
+ }
+ }()
out := &bytes.Buffer{}
e.Out, e.ErrOut = out, out
@@ -108,6 +114,7 @@ func TestCopyFrom(t *testing.T) {
{name: "copy folder with dot contents to higher level", create: "mkdir -p /a/b && touch /a/b/1 /a/b/2", copy: "/a/b/. /b/", expect: "ls -al /b/1 /b/2 /b && ! ls -al /a /b/a /b/b"},
{name: "copy root file to different root name", create: "touch /b", copy: "/b /a", expect: "ls -al /a && ! ls -al /b"},
{name: "copy nested file to different root name", create: "mkdir -p /a && touch /a/b", copy: "/a/b /a", expect: "ls -al /a && ! ls -al /b"},
+ {name: "copy hard links to excluded file", create: "mkdir -p /a/b/c && touch /a/b/c/d && ln /a/b/c/d /a/b/d && ln /a/b/c/d /a/b/e", extra: "RUN mkdir -p /f/g", copy: "/a/b/d /a/b/e /f/g/", expect: "ls -al /f && ls -al /f/g && ls -al /f/g/d /f/g/e"},
{name: "copy file to deeper directory with explicit slash", create: "mkdir -p /a && touch /a/1", copy: "/a/1 /a/b/c/", expect: "ls -al /a/b/c/1 && ! ls -al /a/b/1"},
{name: "copy file to deeper directory without explicit slash", create: "mkdir -p /a && touch /a/1", copy: "/a/1 /a/b/c", expect: "ls -al /a/b/c && ! ls -al /a/b/1"},
{name: "copy directory to deeper directory without explicit slash", create: "mkdir -p /a && touch /a/1", copy: "/a /a/b/c", expect: "ls -al /a/b/c/1 && ! ls -al /a/b/1"},
@@ -125,7 +132,11 @@ func TestCopyFrom(t *testing.T) {
t.Run(name, func(t *testing.T) {
t.Parallel()
e := NewClientExecutor(c)
- defer e.Release()
+ defer func() {
+ for _, err := range e.Release() {
+ t.Errorf("%v", err)
+ }
+ }()
out := &bytes.Buffer{}
e.Out, e.ErrOut = out, out
@@ -170,7 +181,11 @@ func TestShell(t *testing.T) {
}
e := NewClientExecutor(c)
- defer e.Release()
+ defer func() {
+ for _, err := range e.Release() {
+ t.Errorf("%v", err)
+ }
+ }()
out := &bytes.Buffer{}
e.Out, e.ErrOut = out, out
@@ -206,7 +221,11 @@ func TestMultiStageBase(t *testing.T) {
}
e := NewClientExecutor(c)
- defer e.Release()
+ defer func() {
+ for _, err := range e.Release() {
+ t.Errorf("%v", err)
+ }
+ }()
out := &bytes.Buffer{}
e.Out, e.ErrOut = out, out
@@ -256,6 +275,10 @@ func TestMultiStageBase(t *testing.T) {
// TODO: ensure that the final built image has the right UIDs
//
func TestConformanceInternal(t *testing.T) {
+ pwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
testCases := []conformanceTest{
{
Name: "directory",
@@ -347,6 +370,11 @@ func TestConformanceInternal(t *testing.T) {
Dockerfile: "Dockerfile.addall",
},
{
+ Name: "add directories with archives 2",
+ ContextDir: "testdata/add",
+ Dockerfile: "Dockerfile.addslash",
+ },
+ {
Name: "run with JSON",
Dockerfile: "testdata/Dockerfile.run.args",
Output: []*regexp.Regexp{
@@ -375,6 +403,14 @@ func TestConformanceInternal(t *testing.T) {
ContextDir: "testdata/wildcard",
},
{
+ Name: "wildcard leading path",
+ ContextDir: "./testdata/wildcard",
+ },
+ {
+ Name: "wildcard absolute path",
+ ContextDir: filepath.Join(pwd, "testdata", "wildcard"),
+ },
+ {
Name: "volume",
ContextDir: "testdata/volume",
},
@@ -398,6 +434,30 @@ func TestConformanceInternal(t *testing.T) {
Name: "volumeexists",
Dockerfile: "testdata/Dockerfile.volumeexists",
},
+ {
+ Name: "multistage 1",
+ ContextDir: "testdata",
+ Dockerfile: "Dockerfile.multistage",
+ },
+ {
+ Name: "multistage reuse base",
+ ContextDir: "testdata",
+ Dockerfile: "Dockerfile.reusebase",
+ },
+ {
+ Name: "multistage 2",
+ ContextDir: "testdata/multistage",
+ Dockerfile: "Dockerfile",
+ },
+ {
+ Name: "multistage copy",
+ ContextDir: "testdata/copyfrom",
+ },
+ {
+ Name: "multistageconfiginheritance",
+ ContextDir: "testdata/multistage",
+ Dockerfile: "Dockerfile.env",
+ },
}
for i, test := range testCases {
@@ -432,8 +492,8 @@ func TestConformanceExternal(t *testing.T) {
{
Name: "copy and env interaction",
// Tests COPY and other complex interactions of ENV
- ContextDir: "13",
- Dockerfile: "13/Dockerfile",
+ ContextDir: "14/alpine",
+ Dockerfile: "Dockerfile",
Git: "https://github.com/docker-library/postgres.git",
Ignore: []ignoreFunc{
func(a, b *tar.Header) bool {
@@ -470,6 +530,12 @@ func TestTransientMount(t *testing.T) {
}
e := NewClientExecutor(c)
+ defer func() {
+ for _, err := range e.Release() {
+ t.Errorf("%v", err)
+ }
+ }()
+
e.AllowPull = true
e.Directory = "testdata"
e.TransientMounts = []Mount{
@@ -478,7 +544,7 @@ func TestTransientMount(t *testing.T) {
}
e.Tag = fmt.Sprintf("conformance%d", rand.Int63())
- defer c.RemoveImage(e.Tag)
+ defer e.removeImage(e.Tag)
out := &bytes.Buffer{}
e.Out = out
@@ -556,7 +622,7 @@ func conformanceTester(t *testing.T, c *docker.Client, test conformanceTest, i i
dir := tmpDir
contextDir := filepath.Join(dir, test.ContextDir)
- dockerfilePath := filepath.Join(dir, dockerfile)
+ dockerfilePath := filepath.Join(dir, test.ContextDir, dockerfile)
// clone repo or copy the Dockerfile
var input string
@@ -576,24 +642,61 @@ func conformanceTester(t *testing.T, c *docker.Client, test conformanceTest, i i
return
}
}
+ dir = contextDir
case len(test.ContextDir) > 0:
- input = filepath.Join(test.ContextDir, dockerfile)
- dockerfilePath = filepath.Join(test.ContextDir, "Dockerfile")
- contextDir = test.ContextDir
- dir = test.ContextDir
+ hardlinks := new(hardlinkChecker)
+ if err := filepath.Walk(filepath.Join("", test.ContextDir), func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ dest := filepath.Join(dir, path)
+ if info.IsDir() {
+ if err := os.MkdirAll(dest, info.Mode()); err != nil {
+ return err
+ }
+ return os.Chtimes(dest, info.ModTime(), info.ModTime())
+ }
+ if info.Mode()&os.ModeSymlink == os.ModeSymlink {
+ linkTarget, err := os.Readlink(path)
+ if err != nil {
+ return err
+ }
+ return os.Symlink(linkTarget, dest)
+ }
+ if info.Mode().IsRegular() {
+ if hardlinkTarget, ok := hardlinks.Check(info, dest); ok {
+ return os.Link(hardlinkTarget, dest)
+ }
+ if _, err := fileutils.CopyFile(path, dest); err != nil {
+ return err
+ }
+ if err := os.Chmod(dest, info.Mode()&os.ModePerm); err != nil {
+ return err
+ }
+ return os.Chtimes(dest, info.ModTime(), info.ModTime())
+ }
+ return fmt.Errorf("%s: %w", dest, syscall.ENOTSUP)
+ }); err != nil {
+ t.Fatal(err)
+ }
+ contextDir = filepath.Join(dir, test.ContextDir)
+ dockerfilePath = filepath.Join(contextDir, "Dockerfile")
if len(test.Dockerfile) > 0 {
- dockerfilePath = filepath.Join(dir, test.Dockerfile)
+ dockerfilePath = filepath.Join(contextDir, test.Dockerfile)
}
+ dir = contextDir
+ input = dockerfilePath
default:
- input = dockerfile
dockerfilePath = filepath.Join(dir, "Dockerfile")
+ input = dockerfilePath
if _, err := fileutils.CopyFile(filepath.Join("", dockerfile), dockerfilePath); err != nil {
t.Fatal(err)
}
dockerfile = "Dockerfile"
+ dir = contextDir
}
// read the dockerfile
@@ -607,16 +710,15 @@ func conformanceTester(t *testing.T, c *docker.Client, test conformanceTest, i i
t.Errorf("%d: can't parse Dockerfile %q: %v", i, input, err)
return
}
- from, err := imagebuilder.NewBuilder(nil).From(node)
+ builder := imagebuilder.NewBuilder(nil)
+ stages, err := imagebuilder.NewStages(node, builder)
if err != nil {
- t.Errorf("%d: can't get base FROM %q: %v", i, input, err)
+ t.Errorf("%d: error parsing Dockerfile %q: %v", i, input, err)
return
}
- nameFormat := "conformance-dockerbuild-%d-%s-%d"
+ nameFormat := "conformance-dockerbuild-%d-%s-%d-%d"
var toDelete []string
- steps := node.Children
- lastImage := from
ignoreSmallFileChange := func(a, b *tar.Header) bool {
if a == nil || b == nil {
@@ -632,87 +734,148 @@ func conformanceTester(t *testing.T, c *docker.Client, test conformanceTest, i i
dockerOut := &bytes.Buffer{}
imageOut := &bytes.Buffer{}
+ exclude, _ := imagebuilder.ParseDockerignore(contextDir)
if deep {
- // execute each step on both Docker build and the direct builder, comparing as we
- // go
- fail := false
- for j := range steps {
- testFile := dockerfileWithFrom(lastImage, steps[j:j+1])
-
- nameDirect := fmt.Sprintf(nameFormat, i, "direct", j)
- nameDocker := fmt.Sprintf(nameFormat, i, "docker", j)
-
- // run docker build
- if err := ioutil.WriteFile(dockerfilePath, []byte(testFile), 0600); err != nil {
- t.Errorf("%d: unable to update Dockerfile %q: %v", i, dockerfilePath, err)
- break
- }
- in, err := archive.TarWithOptions(dir, &archive.TarOptions{IncludeFiles: []string{"."}})
- if err != nil {
- t.Errorf("%d: unable to generate build context %q: %v", i, dockerfilePath, err)
- break
- }
- if err := c.BuildImage(docker.BuildImageOptions{
- Name: nameDocker,
- Dockerfile: dockerfile,
- RmTmpContainer: true,
- ForceRmTmpContainer: true,
- InputStream: in,
- OutputStream: dockerOut,
- NoCache: len(test.Output) > 0,
- }); err != nil {
- in.Close()
- data, _ := ioutil.ReadFile(testFile)
- t.Errorf("%d: unable to build Docker image %q: %v\n%s\n%s", i, test.Git, err, string(data), dockerOut)
- break
+ // dockerfileWithFrom returns the contents of a new docker file with a different
+ // FROM as the first line, and any --from= arguments in COPY or ADD instructions
+ // replaced with the names of images that we expect to have created at the end
+ // of the stages that built them
+ dockerfileWithFrom := func(from string, steps []*parser.Node, currentStageIndex int) (string, error) {
+ lines := []string{}
+ lines = append(lines, fmt.Sprintf("FROM %s", from))
+ for _, step := range steps {
+ switch strings.ToUpper(step.Value) {
+ case strings.ToUpper(command.Add), strings.ToUpper(command.Copy):
+ line := strings.ToUpper(step.Value)
+ for _, flag := range step.Flags {
+ // replace --from=stageName|stageNumber with --from=stageFinalImage
+ if strings.HasPrefix(flag, "--from=") {
+ stageLabel := strings.TrimPrefix(flag, "--from=")
+ if b, ok := stages.ByName(stageLabel); ok {
+ otherStage := fmt.Sprintf(nameFormat, i, "docker", b.Position, len(b.Node.Children))
+ flag = "--from=" + otherStage
+ } else if stageIndex, err := strconv.Atoi(stageLabel); err == nil {
+ if stageIndex >= currentStageIndex {
+ return "", fmt.Errorf("%q references not-yet-built stage", step.Original)
+ }
+ b := stages[stageIndex]
+ otherStage := fmt.Sprintf(nameFormat, i, "docker", b.Position, len(b.Node.Children))
+ flag = "--from=" + otherStage
+ }
+ }
+ line = line + " " + flag
+ }
+ next := step.Next
+ for next != nil {
+ line = line + " " + next.Value
+ next = next.Next
+ }
+ lines = append(lines, line)
+ default:
+ lines = append(lines, step.Original)
+ }
}
- toDelete = append(toDelete, nameDocker)
+ return strings.Join(lines, "\n"), nil
+ }
- // run direct build
- e := NewClientExecutor(c)
- e.Out, e.ErrOut = imageOut, imageOut
- e.Directory = contextDir
- e.Tag = nameDirect
- b := imagebuilder.NewBuilder(test.Args)
- node, err := imagebuilder.ParseDockerfile(bytes.NewBufferString(testFile))
+ // execute each stage on both Docker build and the direct
+ // builder, comparing as we go
+ for j := range stages {
+ // execute thru each step in this stage on both Docker
+ // build and the direct builder, comparing as we go
+ stageBase, err := builder.From(stages[j].Node)
if err != nil {
- t.Fatalf("%d: %v", i, err)
+ t.Fatalf("%d: %v", j, err)
}
- if err := e.Build(b, node, ""); err != nil {
- t.Errorf("%d: failed to build step %d in dockerfile %q: %s\n%s", i, j, dockerfilePath, steps[j].Original, imageOut)
- break
+ // if the base is the result of a previous stage,
+ // resolve it to that stage's final image here
+ if b, ok := stages.ByName(stageBase); ok {
+ stageBase = fmt.Sprintf(nameFormat, i, "docker", b.Position, len(b.Node.Children))
}
- toDelete = append(toDelete, nameDirect)
+ steps := stages[j].Node.Children
+ for k := range steps {
+ // construct the Dockerfile
+ testFile, err := dockerfileWithFrom(stageBase, steps[0:k+1], j)
+ if err != nil {
+ t.Fatalf("%d: unable to reconstruct Dockerfile %q: %v", i, dockerfilePath, err)
+ }
- // only compare filesystem on layers that change the filesystem
- mutation := steps[j].Value == command.Add || steps[j].Value == command.Copy || steps[j].Value == command.Run
- // metadata must be strictly equal
- if !equivalentImages(
- t, c, nameDocker, nameDirect, mutation,
- metadataEqual,
- append(ignoreFuncs{ignoreSmallFileChange}, test.Ignore...)...,
- ) {
- t.Errorf("%d: layered Docker build was not equivalent to direct layer image metadata %s", i, input)
- fail = true
- }
+ nameDirect := fmt.Sprintf(nameFormat, i, "direct", j, k+1)
+ nameDocker := fmt.Sprintf(nameFormat, i, "docker", j, k+1)
- lastImage = nameDocker
- }
+ // run docker build for this stage thru this step
+ if err := ioutil.WriteFile(dockerfilePath, []byte(testFile), 0600); err != nil {
+ t.Fatalf("%d: unable to update Dockerfile %q: %v", i, dockerfilePath, err)
+ }
+ in, err := archive.TarWithOptions(dir, &archive.TarOptions{IncludeFiles: []string{"."}, ExcludePatterns: exclude})
+ if err != nil {
+ t.Fatalf("%d: unable to generate build context %q: %v", i, dockerfilePath, err)
+ }
+ var args []docker.BuildArg
+ for k, v := range test.Args {
+ args = append(args, docker.BuildArg{Name: k, Value: v})
+ }
+ if err := c.BuildImage(docker.BuildImageOptions{
+ Name: nameDocker,
+ Dockerfile: dockerfile,
+ RmTmpContainer: true,
+ ForceRmTmpContainer: true,
+ InputStream: in,
+ OutputStream: dockerOut,
+ BuildArgs: args,
+ NoCache: len(test.Output) > 0,
+ }); err != nil {
+ in.Close()
+ data, _ := ioutil.ReadFile(dockerfilePath)
+ t.Fatalf("%d: unable to build Docker image %q: %v\n%s\n%s", i, test.Git, err, string(data), dockerOut)
+ }
+ in.Close()
+ toDelete = append([]string{nameDocker}, toDelete...)
- if fail {
- t.Fatalf("%d: Conformance test failed for %s", i, input)
+ // run direct build of this stage thru this step
+ e := NewClientExecutor(c)
+ defer func() {
+ for _, err := range e.Release() {
+ t.Errorf("%v", err)
+ }
+ }()
+ e.Out, e.ErrOut = imageOut, imageOut
+ e.Directory = dir
+ e.Tag = nameDirect
+ b := imagebuilder.NewBuilder(test.Args)
+ node, err := imagebuilder.ParseDockerfile(bytes.NewBufferString(testFile))
+ if err != nil {
+ t.Fatalf("%d: %v", i, err)
+ }
+ if err := e.Build(b, node, ""); err != nil {
+ t.Fatalf("%d: failed to build through step %d/%d in dockerfile %q: %s\n%s", i, j, k, dockerfilePath, steps[k].Original, imageOut)
+ }
+ toDelete = append([]string{nameDirect}, toDelete...)
+
+ // only compare filesystem on layers that change the filesystem
+ mutation := steps[k].Value == command.Add || steps[k].Value == command.Copy || steps[k].Value == command.Run
+ // metadata must be strictly equal
+ if !equivalentImages(
+ t, c, nameDocker, nameDirect, mutation,
+ metadataEqual,
+ append(ignoreFuncs{ignoreSmallFileChange}, test.Ignore...)...,
+ ) {
+ data, _ := ioutil.ReadFile(dockerfilePath)
+ t.Logf("Dockerfile:\n%s", data)
+ t.Fatalf("%d: layered Docker build was not equivalent to direct layer image metadata %s", i, input)
+ }
+ }
}
-
} else {
- exclude, _ := imagebuilder.ParseDockerignore(dir)
- //exclude = append(filtered, ".dockerignore")
+ // run docker build
in, err := archive.TarWithOptions(dir, &archive.TarOptions{IncludeFiles: []string{"."}, ExcludePatterns: exclude})
if err != nil {
t.Errorf("%d: unable to generate build context %q: %v", i, dockerfilePath, err)
return
}
- nameDocker := fmt.Sprintf(nameFormat, i, "docker", 0)
+ stageSteps := stages[len(stages)-1].Node.Children
+ nameDocker := fmt.Sprintf(nameFormat, i, "docker", len(stages)-1, len(stageSteps))
var args []docker.BuildArg
for k, v := range test.Args {
args = append(args, docker.BuildArg{Name: k, Value: v})
@@ -731,27 +894,45 @@ func conformanceTester(t *testing.T, c *docker.Client, test conformanceTest, i i
t.Errorf("%d: unable to build Docker image %q: %v\n%s", i, test.Git, err, dockerOut)
return
}
- lastImage = nameDocker
- toDelete = append(toDelete, nameDocker)
- }
+ in.Close()
+ toDelete = append([]string{nameDocker}, toDelete...)
- // if we ran more than one step, compare the squashed output with the docker build output
- if len(steps) > 1 || !deep {
- nameDirect := fmt.Sprintf(nameFormat, i, "direct", len(steps)-1)
- e := NewClientExecutor(c)
- e.Out, e.ErrOut = imageOut, imageOut
- e.Directory = contextDir
- e.Tag = nameDirect
+ // run direct build
b := imagebuilder.NewBuilder(test.Args)
node, err := imagebuilder.ParseDockerfile(bytes.NewBuffer(data))
if err != nil {
t.Fatalf("%d: %v", i, err)
}
- if err := e.Build(b, node, ""); err != nil {
+ stages, err := imagebuilder.NewStages(node, b)
+ if err != nil {
+ t.Errorf("%v", err)
+ return
+ }
+ if len(stages) == 0 {
+ t.Error("parsing Dockerfile produced no stages")
+ return
+ }
+ nameDirect := fmt.Sprintf(nameFormat, i, "direct", len(stages)-1, len(stageSteps))
+ e := NewClientExecutor(c)
+ defer func() {
+ for _, err := range e.Release() {
+ t.Errorf("%v", err)
+ }
+ }()
+ e.Out, e.ErrOut = imageOut, imageOut
+ e.Directory = dir
+ e.Tag = nameDirect
+ lastExecutor, err := e.Stages(b, stages, "")
+ if err != nil {
+ t.Errorf("%v", err)
+ return
+ }
+ if err := lastExecutor.Commit(stages[len(stages)-1].Builder); err != nil {
t.Errorf("%d: failed to build complete image in %q: %v\n%s", i, input, err, imageOut)
} else {
+ toDelete = append([]string{nameDirect}, toDelete...)
if !equivalentImages(
- t, c, lastImage, nameDirect, true,
+ t, c, nameDocker, nameDirect, true,
// metadata should be loosely equivalent, but because we squash and because of limitations
// in docker commit, there are some differences
metadataLayerEquivalent,
@@ -868,7 +1049,7 @@ func equivalentImages(t *testing.T, c *docker.Client, a, b string, testFilesyste
}
if !metadataFn(imageA.Config, imageB.Config) {
- t.Errorf("generated image metadata did not match:\n%#v\n%#v", imageA.Config, imageB.Config)
+ t.Errorf("generated image metadata did not match (%s, %s):\n%#v\n%#v", a, b, imageA.Config, imageB.Config)
return false
}
@@ -884,7 +1065,7 @@ func equivalentImages(t *testing.T, c *docker.Client, a, b string, testFilesyste
delete(differs, k)
continue
}
- t.Errorf("%s %s differs:\n%#v\n%#v", a, k, v[0].Header, v[1].Header)
+ t.Errorf("%s and %s differ at %s:\n%#v\n%#v", a, b, k, v[0].Header, v[1].Header)
}
for k, v := range onlyA {
if ignoreFuncs(ignoreFns).Ignore(v.Header, nil) {
@@ -899,24 +1080,13 @@ func equivalentImages(t *testing.T, c *docker.Client, a, b string, testFilesyste
}
}
if len(onlyA)+len(onlyB)+len(differs) > 0 {
- t.Errorf("a=%v b=%v diff=%v", onlyA, onlyB, differs)
+ t.Errorf("a(%s)=%v b(%s)=%v diff=%v", a, onlyA, b, onlyB, differs)
return false
}
}
return true
}
-// dockerfileWithFrom returns the contents of a new docker file with a different
-// FROM as the first line.
-func dockerfileWithFrom(from string, steps []*parser.Node) string {
- lines := []string{}
- lines = append(lines, fmt.Sprintf("FROM %s", from))
- for _, step := range steps {
- lines = append(lines, step.Original)
- }
- return strings.Join(lines, "\n")
-}
-
// envMap returns a map from a list of environment variables.
func envMap(env []string) map[string]string {
out := make(map[string]string)
@@ -1048,3 +1218,21 @@ func imageFSMetadata(c *docker.Client, name string) (map[string]tarHeader, error
<-ch
return result, nil
}
+
+type hardlinkChecker struct {
+ known map[hardlinkCheckerKey]string
+}
+
+func (h *hardlinkChecker) Check(info os.FileInfo, name string) (string, bool) {
+ if h.known == nil {
+ h.known = make(map[hardlinkCheckerKey]string)
+ }
+ key := h.makeHardlinkCheckerKey(info)
+ if key != nil {
+ if name, ok := h.known[*key]; ok {
+ return name, ok
+ }
+ h.known[*key] = name
+ }
+ return "", false
+}
diff --git a/dockerclient/conformance_unix_test.go b/dockerclient/conformance_unix_test.go
new file mode 100644
index 0000000..598ca9a
--- /dev/null
+++ b/dockerclient/conformance_unix_test.go
@@ -0,0 +1,20 @@
+// +build conformance,!windows
+
+package dockerclient
+
+import (
+ "os"
+ "syscall"
+)
+
+type hardlinkCheckerKey struct {
+ device, inode uint64
+}
+
+func (h *hardlinkChecker) makeHardlinkCheckerKey(info os.FileInfo) *hardlinkCheckerKey {
+ sys := info.Sys()
+ if stat, ok := sys.(*syscall.Stat_t); ok && (stat.Nlink > 1) {
+ return &hardlinkCheckerKey{device: uint64(stat.Dev), inode: uint64(stat.Ino)}
+ }
+ return nil
+}
diff --git a/dockerclient/conformance_windows_test.go b/dockerclient/conformance_windows_test.go
new file mode 100644
index 0000000..295ddf1
--- /dev/null
+++ b/dockerclient/conformance_windows_test.go
@@ -0,0 +1,14 @@
+// +build conformance,windows
+
+package dockerclient
+
+import (
+ "os"
+)
+
+type hardlinkCheckerKey struct {
+}
+
+func (h *hardlinkChecker) makeHardlinkCheckerKey(info os.FileInfo) *hardlinkCheckerKey {
+ return nil
+}
diff --git a/dockerclient/copyinfo.go b/dockerclient/copyinfo.go
index dfdfa19..e7b5a5d 100644
--- a/dockerclient/copyinfo.go
+++ b/dockerclient/copyinfo.go
@@ -32,6 +32,9 @@ func CalcCopyInfo(origPath, rootPath string, allowWildcards bool) ([]CopyInfo, e
func calcCopyInfo(origPath, rootPath string, allowWildcards, explicitDir bool) ([]CopyInfo, error) {
origPath = trimLeadingPath(origPath)
+ if !filepath.IsAbs(rootPath) {
+ rootPath = trimLeadingPath(rootPath)
+ }
// Deal with wildcards
if allowWildcards && containsWildcards(origPath) {
matchPath := filepath.Join(rootPath, origPath)
diff --git a/dockerclient/copyinfo_test.go b/dockerclient/copyinfo_test.go
index 2485444..face0d2 100644
--- a/dockerclient/copyinfo_test.go
+++ b/dockerclient/copyinfo_test.go
@@ -253,7 +253,7 @@ func TestCalcCopyInfo(t *testing.T) {
t.Errorf("did not see paths: %#v", expect)
}
- options, err := archiveOptionsFor(infos, test.dstPath, test.excludes, testDirectoryCheck(test.check))
+ options, err := archiveOptionsFor("", infos, test.dstPath, test.excludes, testDirectoryCheck(test.check))
if err != nil {
t.Fatal(err)
}
diff --git a/dockerclient/testdata/Dockerfile.copyfrom_13 b/dockerclient/testdata/Dockerfile.copyfrom_13
new file mode 100644
index 0000000..42c5db8
--- /dev/null
+++ b/dockerclient/testdata/Dockerfile.copyfrom_13
@@ -0,0 +1,5 @@
+FROM busybox as base
+RUN touch /a
+FROM busybox
+COPY --from=0 /a /
+RUN ls -al /a
diff --git a/dockerclient/testdata/Dockerfile.copyfrom_14 b/dockerclient/testdata/Dockerfile.copyfrom_14
new file mode 100644
index 0000000..9df1cb6
--- /dev/null
+++ b/dockerclient/testdata/Dockerfile.copyfrom_14
@@ -0,0 +1,5 @@
+FROM busybox
+RUN touch /a
+FROM busybox
+COPY --from=0 /a /
+RUN ls -al /a
diff --git a/dockerclient/testdata/Dockerfile.multistage b/dockerclient/testdata/Dockerfile.multistage
new file mode 100644
index 0000000..638fd33
--- /dev/null
+++ b/dockerclient/testdata/Dockerfile.multistage
@@ -0,0 +1,24 @@
+FROM alpine as multistagebase
+COPY multistage/dir/a.txt /
+WORKDIR /tmp
+RUN touch /base.txt tmp.txt
+
+FROM multistagebase as second
+COPY dir/file /
+RUN touch /second.txt
+
+FROM alpine
+COPY --from=1 /second.txt /third.txt
+
+FROM alpine
+COPY --from=2 /third.txt /fourth.txt
+
+FROM alpine
+COPY --from=multistagebase /base.txt /fifth.txt
+COPY --from=multistagebase ./tmp/tmp.txt /tmp.txt
+# "golang" has a default working directory of /go, and /go/src is a directory
+COPY --from=golang go/src /src
+
+FROM multistagebase as final
+COPY copy/script /
+RUN touch /final.txt
diff --git a/dockerclient/testdata/add/Dockerfile b/dockerclient/testdata/add/Dockerfile
index 01661bd..0608eee 100644
--- a/dockerclient/testdata/add/Dockerfile
+++ b/dockerclient/testdata/add/Dockerfile
@@ -6,3 +6,8 @@ ADD archived.tar.bz2 /archived-bz2/
ADD archived.tar.xz /archived-xz/
ADD archived.txt archived.tar.xz archived.tar.bz2 /archived-mixed/
ADD archived.txt /archived.tar.xz ./archived.tar.bz2 /archived-mixed-path-variations/
+ADD archived.txt* /archived-globbed-plain/
+ADD archived.tar.gz* /archived-globbed-gz/
+ADD archived.tar.bz2* /archived-globbed-bz2/
+ADD archived.tar.xz* /archived-globbed-xz/
+ADD archived.* /archived-globbed/
diff --git a/dockerclient/testdata/add/Dockerfile.addslash b/dockerclient/testdata/add/Dockerfile.addslash
new file mode 100644
index 0000000..89a4581
--- /dev/null
+++ b/dockerclient/testdata/add/Dockerfile.addslash
@@ -0,0 +1,2 @@
+FROM centos:7
+ADD / /
diff --git a/dockerclient/testdata/copychown/Dockerfile b/dockerclient/testdata/copychown/Dockerfile
index 3736d6b..6d7649f 100644
--- a/dockerclient/testdata/copychown/Dockerfile
+++ b/dockerclient/testdata/copychown/Dockerfile
@@ -1,10 +1,20 @@
FROM centos:7
-COPY --chown=1:2 script /usr/bin/script.12
-COPY --chown=1:adm script /usr/bin/script.1-adm
-COPY --chown=1 script /usr/bin/script.1
-COPY --chown=lp:adm script /usr/bin/script.lp-adm
-COPY --chown=2:mail script /usr/bin/script.2-mail
-COPY --chown=2 script /usr/bin/script.2
-COPY --chown=bin script /usr/bin/script.bin
-COPY --chown=lp script /usr/bin/script.lp
-COPY --chown=3 script script2 /usr/local/bin/
+COPY --chown=1:2 script /usr/bin/script.12
+COPY --chown=1:adm script /usr/bin/script.1-adm
+COPY --chown=1 script /usr/bin/script.1
+COPY --chown=lp:adm script /usr/bin/script.lp-adm
+COPY --chown=2:mail script /usr/bin/script.2-mail
+COPY --chown=2 script /usr/bin/script.2
+COPY --chown=bin script /usr/bin/script.bin
+COPY --chown=lp script /usr/bin/script.lp
+COPY --chown=3 script script2 /usr/local/bin/
+RUN rm -fr /var/created-directory
+COPY --chown=2097152 script script2 /var/created/directory/
+RUN rm -fr /no-such-directory
+COPY --chown=3 script script2 /no-such-directory/
+RUN rm -fr /new-workdir
+WORKDIR /new-workdir/several/levels/deep
+COPY --chown=3 script script2 no-such-directory/
+WORKDIR ../deeper
+COPY --chown=3 script script2 no-such-directory-either/
+COPY --chown=3 script script2 ../no-such-subdirectory/
diff --git a/dockerclient/testdata/copyfrom/Dockerfile b/dockerclient/testdata/copyfrom/Dockerfile
index a0cf363..6634ec7 100644
--- a/dockerclient/testdata/copyfrom/Dockerfile
+++ b/dockerclient/testdata/copyfrom/Dockerfile
@@ -1,4 +1,15 @@
FROM centos:7 as base
RUN mkdir -p /a/blah && touch /a/blah/1 /a/blah/2
+RUN mkdir -m 711 /711 && touch /711/711.txt
+RUN mkdir -m 755 /755 && touch /755/755.txt
+RUN mkdir -m 777 /777 && touch /777/777.txt
FROM centos:7
COPY --from=base /a/blah/* /blah/
+RUN rm -fr /711 /755 /777
+COPY --from=0 /711 /711
+COPY --from=0 /755 /755
+COPY --from=0 /777 /777
+RUN mkdir /precreated /precreated/711 /precreated/755 /precreated/777
+COPY --from=0 /711 /precreated/711
+COPY --from=0 /755 /precreated/755
+COPY --from=0 /777 /precreated/777
diff --git a/dockerclient/testdata/multistage/Dockerfile.env b/dockerclient/testdata/multistage/Dockerfile.env
new file mode 100644
index 0000000..609aeb4
--- /dev/null
+++ b/dockerclient/testdata/multistage/Dockerfile.env
@@ -0,0 +1,15 @@
+# Taken from #209
+
+FROM alpine AS base
+ENV FOO=foo
+RUN echo FOO=$FOO
+
+FROM base AS devel
+ENV BAR=bar
+RUN echo FOO=$FOO BAR=$BAR
+
+FROM devel AS devel2
+RUN echo FOO=$FOO BAR=$BAR
+
+FROM devel2 AS devel3
+RUN echo FOO=$FOO BAR=$BAR
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..72dc624
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,18 @@
+module github.com/openshift/imagebuilder
+
+go 1.16
+
+require (
+ github.com/containerd/containerd v1.5.9
+ github.com/containers/storage v1.37.0
+ github.com/docker/distribution v2.7.1+incompatible
+ github.com/docker/docker v20.10.12+incompatible
+ github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11 // indirect
+ github.com/fsouza/go-dockerclient v1.7.7
+ github.com/pkg/errors v0.9.1
+ github.com/sirupsen/logrus v1.8.1
+ github.com/stretchr/testify v1.7.0
+ golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
+ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
+ k8s.io/klog v1.0.0
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..6125402
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,1003 @@
+bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
+github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
+github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
+github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
+github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
+github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0=
+github.com/Microsoft/hcsshim v0.8.23 h1:47MSwtKGXet80aIn+7h4YI6fwPmwIghAnsx2aOUrG2M=
+github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
+github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
+github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+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/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
+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/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=
+github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
+github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
+github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
+github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
+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/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1/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=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
+github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
+github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
+github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
+github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
+github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E=
+github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
+github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
+github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
+github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ=
+github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
+github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
+github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
+github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
+github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
+github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
+github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
+github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
+github.com/containerd/containerd v1.5.9 h1:rs6Xg1gtIxaeyG+Smsb/0xaSDu1VgFhOCKBXxMxbsF4=
+github.com/containerd/containerd v1.5.9/go.mod h1:fvQqCfadDGga5HZyn3j4+dx56qj2I9YwBrlSdalvJYQ=
+github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
+github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
+github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
+github.com/containerd/continuity v0.1.0 h1:UFRRY5JemiAhPZrr/uE0n8fMTLcZsUvySPr1+D7pgr8=
+github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
+github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
+github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
+github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
+github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0=
+github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA=
+github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
+github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms=
+github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
+github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/stargz-snapshotter/estargz v0.9.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
+github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
+github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
+github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
+github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
+github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
+github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
+github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
+github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
+github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
+github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
+github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
+github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
+github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/containers/storage v1.37.0 h1:HVhDsur6sx889ZIZ1d1kEiOzv3gsr5q0diX2VZmOdSg=
+github.com/containers/storage v1.37.0/go.mod h1:kqeJeS0b7DO2ZT1nVWs0XufrmPFbgV3c+Q/45RlH6r4=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
+github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
+github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
+github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
+github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
+github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
+github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
+github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v20.10.12+incompatible h1:CEeNmFM0QZIsJCZKMkZx0ZcahTiewkrgiwfYD+dfl1U=
+github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11 h1:IPrmumsT9t5BS7XcPhgsCTlkWbYg80SEXUzDpReaU6Y=
+github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11/go.mod h1:a6bNUGTbQBsY6VRHTr4h/rkOXjl244DyRD0tx3fgq4Q=
+github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
+github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
+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/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=
+github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsouza/go-dockerclient v1.7.7 h1:/pLili4Sj42vpzNkjqag8vpsN0ObuusT1EH/MvGX9+4=
+github.com/fsouza/go-dockerclient v1.7.7/go.mod h1:njNCXvoZj3sLPjf3yO0DPHf1mdLdCPDYPc14GskKA4Y=
+github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
+github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+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-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-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=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
+github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+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.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+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/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=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
+github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+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/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+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/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
+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/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
+github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
+github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
+github.com/moby/sys/mount v0.2.0 h1:WhCW5B355jtxndN5ovugJlMFJawbUODuW8fSnEH6SSM=
+github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=
+github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
+github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
+github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
+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/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=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
+github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
+github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
+github.com/opencontainers/runc v1.0.3 h1:1hbqejyQWCJBvtKAfdO0b1FmaEf2z/bxnjqbARass5k=
+github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
+github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
+github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
+github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
+github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
+github.com/opencontainers/selinux v1.8.5/go.mod h1:HTvjPFoGMbpQsG886e3lQwnsRWtE4TC1OF3OUvG9FAo=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+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/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=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+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=
+github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+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/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=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
+github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
+github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
+github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/tchap/go-patricia v2.3.0+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
+github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
+github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
+github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
+github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
+go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
+go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+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/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=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs=
+golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+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=
+golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+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=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
+k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
+k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
+k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
+k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
+k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
+k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
+k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
+k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
+k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
+k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
+k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
+k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
+k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
+k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
+k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
+k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
+k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
+k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/imagebuilder.spec b/imagebuilder.spec
index ec8cda5..6a88a4f 100644
--- a/imagebuilder.spec
+++ b/imagebuilder.spec
@@ -12,7 +12,7 @@
#
%global golang_version 1.8.1
-%{!?version: %global version 1.2.1}
+%{!?version: %global version 1.2.3}
%{!?release: %global release 1}
%global package_name imagebuilder
%global product_name Container Image Builder
diff --git a/internals.go b/internals.go
index f33dc70..d4b9539 100644
--- a/internals.go
+++ b/internals.go
@@ -52,7 +52,7 @@ func hasSlash(input string) bool {
// makeAbsolute ensures that the provided path is absolute.
func makeAbsolute(dest, workingDir string) string {
- // Twiddle the destination when its a relative path - meaning, make it
+ // Twiddle the destination when it's a relative path - meaning, make it
// relative to the WORKINGDIR
if dest == "." {
if !hasSlash(workingDir) {
diff --git a/vendor.conf b/vendor.conf
deleted file mode 100644
index 8074ce8..0000000
--- a/vendor.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
-github.com/containerd/containerd v1.3.0
-github.com/containers/storage v1.2
-github.com/docker/docker b68221c37ee597950364788204546f9c9d0e46a1
-github.com/docker/go-connections 97c2040d34dfae1d1b1275fa3a78dbdd2f41cf7e
-github.com/docker/go-units 2fb04c6466a548a03cb009c5569ee1ab1e35398e
-github.com/fsouza/go-dockerclient openshift-4.0 https://github.com/openshift/go-dockerclient.git
-github.com/gogo/protobuf c5a62797aee0054613cc578653a16c6237fef080
-github.com/konsorten/go-windows-terminal-sequences f55edac94c9bbba5d6182a4be46d86a2c9b5b50e
-github.com/Microsoft/go-winio 1a8911d1ed007260465c3bfbbc785ac6915a0bb8
-github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512
-github.com/opencontainers/go-digest ac19fd6e7483ff933754af248d80be865e543d22
-github.com/opencontainers/image-spec 243ea084a44451d27322fed02b682d99e2af3ba9
-github.com/opencontainers/runc 923a8f8a9a07aceada5fc48c4d37e905d9b019b5
-github.com/pkg/errors 27936f6d90f9c8e1145f11ed52ffffbfdb9e0af7
-github.com/pquerna/ffjson d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac
-github.com/sirupsen/logrus d7b6bf5e4d26448fd977d07d745a2a66097ddecb
-golang.org/x/crypto ff983b9c42bc9fbf91556e191cc8efb585c16908
-golang.org/x/net 45ffb0cd1ba084b73e26dee67e667e1be5acce83
-golang.org/x/sys 7fbe1cd0fcc20051e1fcb87fbabec4a1bacaaeba
-k8s.io/klog 8e90cee79f823779174776412c13478955131846
-google.golang.org/grpc 6eaf6f47437a6b4e2153a190160ef39a92c7eceb # v1.23.0
-github.com/golang/protobuf v1.2.0
-google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
-