From b1bdbfcb0737b8719a7faebd57bef2a7fcb50304 Mon Sep 17 00:00:00 2001 From: Alfred Krohmer Date: Tue, 7 Jul 2020 16:39:55 +0200 Subject: [PATCH] Initial commit --- .gitignore | 1 + Dockerfile | 13 ++ README.md | 76 +++++++++ aws-efs-csi-pv-provisioner.go | 226 ++++++++++++++++++++++++++ aws-efs-csi-pv-provisioner_test.go | 142 +++++++++++++++++ deploy/deployment.yaml | 27 ++++ deploy/pv.yaml | 18 +++ deploy/pvc.yaml | 11 ++ deploy/rbac.yaml | 56 +++++++ deploy/sc.yaml | 8 + docs/overview.drawio | 1 + docs/overview.svg | 3 + go.mod | 18 +++ go.sum | 248 +++++++++++++++++++++++++++++ 14 files changed, 848 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 aws-efs-csi-pv-provisioner.go create mode 100644 aws-efs-csi-pv-provisioner_test.go create mode 100644 deploy/deployment.yaml create mode 100644 deploy/pv.yaml create mode 100644 deploy/pvc.yaml create mode 100644 deploy/rbac.yaml create mode 100644 deploy/sc.yaml create mode 100644 docs/overview.drawio create mode 100644 docs/overview.svg create mode 100644 go.mod create mode 100644 go.sum diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df7e53c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/efs-csi-pv-provisioner diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..be158e9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.14 AS build + +WORKDIR /app + +ADD ./ /app/ +RUN go build -ldflags '-extldflags "-fno-PIC -static"' -buildmode pie -tags 'osusergo netgo static_build' . && strip efs-csi-pv-provisioner +RUN go test . + +FROM scratch + +ENTRYPOINT ["/efs-csi-pv-provisioner"] + +COPY --from=build /app/efs-csi-pv-provisioner / diff --git a/README.md b/README.md new file mode 100644 index 0000000..dfcddfe --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# AWS EFS CSI PV provisioner + +Kubernetes CSI driver to dynamically provisions Persistent Volumes (PVs) in response to user-requested Persistent Volume Clains (PVCs). Each PV / PVC is a subdirectory on a single, cluster-wide EFS file system. Works in conjunction with the [AWS EFS CSI driver](https://github.com/kubernetes-sigs/aws-efs-csi-driver). + +## Installation + +1. Create an EFS filesystem and mount targets for your cluster. +2. Install the [AWS EFS CSI driver](https://github.com/kubernetes-sigs/aws-efs-csi-driver) with a corresponding `StorageClass` called `efs-sc`. +3. Build a Docker image with the Dockerfile in this repository and push it into a repository. Put the image URL into `deploy/deployment.yaml`. +4. Put your EFS file system IDs into `deploy/deployment.yaml` and `deploy/pv.yaml`. +5. (Optional) Modify the desired mount options in `deploy/pv.yaml` and `deploy/sc.yaml` (e.g. to disable TLS and IAM if not needed). +6. Apply the manifests: `kubectl -n kube-system apply -f deploy/` + +### Creating a PVC + +Apply the following manifest: + +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: my-efs-pvc + namespace: default +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Mi # doesn't matter but is a required field + storageClassName: efs + volumeMode: Filesystem +``` + +A corresponding PV called `pvc-` will be created bound to the PVC. This PV is utilizing the AWS EFS CSI driver. A subdirectory called `--` will be created on the configured EFS file system: + +```yaml +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pvc-cdd36709-bd3b-11ea-9990-12db9e7ffa3d +spec: + accessModes: + - ReadWriteMany + capacity: + storage: 1Mi + claimRef: + apiVersion: v1 + kind: PersistentVolumeClaim + name: my-efs-pvc + namespace: default + resourceVersion: "836626609" + uid: cdd36709-bd3b-11ea-9990-12db9e7ffa3d + csi: + driver: efs.csi.aws.com + volumeHandle: fs-12345678:/persistentvolumes/default-my-efs-pvc-pvc-cdd36709-bd3b-11ea-9990-12db9e7ffa3d + mountOptions: + - tls + - iam + persistentVolumeReclaimPolicy: Delete + storageClassName: efs + volumeMode: Filesystem +status: + phase: Bound +``` + +When a pod is requesting to have this PVC mounted, the AWS EFS CSI driver daemonset will take care of executing the actual mount. The AWS EFS CSI PV provisioner in this repository is only responsible for creating the PVs in response to PVCs. + +## "How it works" overview diagram + +![](docs/overview.svg) + +## TODOs + +* create CI to build and push Docker image +* provide Helm chart +* potentially integerate into AWS EFS CSI driver diff --git a/aws-efs-csi-pv-provisioner.go b/aws-efs-csi-pv-provisioner.go new file mode 100644 index 0000000..8742689 --- /dev/null +++ b/aws-efs-csi-pv-provisioner.go @@ -0,0 +1,226 @@ +package main + +import ( + "flag" + "fmt" + "os" + "path" + "path/filepath" + "strconv" + "strings" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/klog" + "sigs.k8s.io/sig-storage-lib-external-provisioner/controller" + "sigs.k8s.io/sig-storage-lib-external-provisioner/gidallocator" +) + +const provisionerName = "aws.k8s.logmein.com/efs-csi-pv-provisioner" +const efsCsiDriverName = "efs.csi.aws.com" + +type efsProvisioner struct { + fileSystemID string + mountPoint string + subPath string + allocator gidallocator.Allocator +} + +var _ controller.Provisioner = &efsProvisioner{} + +// Provision creates a storage asset and returns a PV object representing it. +func (p *efsProvisioner) Provision(options controller.ProvisionOptions) (*v1.PersistentVolume, error) { + if options.PVC.Spec.Selector != nil { + return nil, fmt.Errorf("claim.Spec.Selector is not supported") + } + + gidAllocate := true + for k, v := range options.StorageClass.Parameters { + switch strings.ToLower(k) { + case "gidmin": + // Let allocator handle + case "gidmax": + // Let allocator handle + case "gidallocate": + b, err := strconv.ParseBool(v) + if err != nil { + return nil, fmt.Errorf("invalid value %s for parameter %s: %v", v, k, err) + } + gidAllocate = b + } + } + + var gid *int + if gidAllocate { + allocate, err := p.allocator.AllocateNext(options) + if err != nil { + return nil, err + } + gid = &allocate + } + + err := p.createVolume(p.getLocalPath(options), gid) + if err != nil { + return nil, err + } + + mountOptions := []string{} + if options.StorageClass.MountOptions != nil { + mountOptions = options.StorageClass.MountOptions + } + + pv := &v1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{ + Name: options.PVName, + }, + Spec: v1.PersistentVolumeSpec{ + PersistentVolumeReclaimPolicy: *options.StorageClass.ReclaimPolicy, + AccessModes: options.PVC.Spec.AccessModes, + Capacity: v1.ResourceList{ + v1.ResourceName(v1.ResourceStorage): options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)], + }, + StorageClassName: "efs-sc", + PersistentVolumeSource: v1.PersistentVolumeSource{ + CSI: &v1.CSIPersistentVolumeSource{ + Driver: efsCsiDriverName, + VolumeHandle: fmt.Sprintf("%s:%s", p.fileSystemID, p.getRemotePath(options)), + }, + }, + MountOptions: mountOptions, + }, + } + + if gidAllocate { + pv.ObjectMeta.Annotations = map[string]string{ + gidallocator.VolumeGidAnnotationKey: strconv.FormatInt(int64(*gid), 10), + } + } + + return pv, nil +} + +func (p *efsProvisioner) createVolume(path string, gid *int) error { + perm := os.FileMode(0777) + if gid != nil { + perm = os.FileMode(0771 | os.ModeSetgid) + } + + if err := os.MkdirAll(path, perm); err != nil { + return err + } + + // Due to umask, need to chmod + if err := os.Chmod(path, perm); err != nil { + os.RemoveAll(path) + return err + } + + if gid != nil { + if err := os.Chown(path, os.Getuid(), *gid); err != nil { + os.RemoveAll(path) + return err + } + } + + return nil +} + +func (p *efsProvisioner) getLocalPath(options controller.ProvisionOptions) string { + return path.Join(p.mountPoint, "/", p.subPath, "/", p.getDirectoryName(options)) +} + +func (p *efsProvisioner) getRemotePath(options controller.ProvisionOptions) string { + return path.Join("/", p.subPath, "/", p.getDirectoryName(options)) +} + +func (p *efsProvisioner) getDirectoryName(options controller.ProvisionOptions) string { + return options.PVC.Namespace + "-" + options.PVC.Name + "-" + options.PVName +} + +// Delete removes the storage asset that was created by Provision represented +// by the given PV. +func (p *efsProvisioner) Delete(volume *v1.PersistentVolume) error { + //TODO ignorederror + err := p.allocator.Release(volume) + if err != nil { + return err + } + + path, err := p.getLocalPathToDelete(volume.Spec.CSI) + if err != nil { + return err + } + + if err := os.RemoveAll(path); err != nil { + return err + } + + return nil +} + +func (p *efsProvisioner) getLocalPathToDelete(csi *v1.CSIPersistentVolumeSource) (string, error) { + if csi.Driver != efsCsiDriverName { + return "", fmt.Errorf("volume's driver %s is not %s", csi.Driver, efsCsiDriverName) + } + + parts := strings.Split(csi.VolumeHandle, ":") + if len(parts) != 2 { + return "", fmt.Errorf("invalid volumeHandle: %s", csi.VolumeHandle) + } + + if parts[0] != p.fileSystemID { + return "", fmt.Errorf("file system ID %s in volumeHandle doesn't match configured file system ID %s", parts[0], p.fileSystemID) + } + + subPath := filepath.Clean(parts[1]) + prefix := path.Join("/", p.subPath) + "/" + if !strings.HasPrefix(subPath, prefix) || subPath == prefix { + return "", fmt.Errorf("invalid subpath %s in volume", parts[1]) + } + + return path.Join(p.mountPoint, "/", parts[1]), nil +} + +func main() { + var fileSystemID, mountPoint, subPath string + flag.StringVar(&fileSystemID, "file-system-id", "", "the ID of the EFS file system (fs-abcdefg)") + flag.StringVar(&mountPoint, "mountpoint", "/efs", "the path in this pod where the EFS file system is mounted") + flag.StringVar(&subPath, "subpath", "/persistentvolumes", "the subpath in the EFS file system that will be used for persistent volumes") + flag.Parse() + flag.Set("logtostderr", "true") + + config, err := rest.InClusterConfig() + if err != nil { + klog.Fatalf("Failed to create config: %v", err) + } + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + klog.Fatalf("Failed to create client: %v", err) + } + + // The controller needs to know what the server version is because out-of-tree + // provisioners aren't officially supported until 1.5 + serverVersion, err := clientset.Discovery().ServerVersion() + if err != nil { + klog.Fatalf("Error getting server version: %v", err) + } + + efsProvisioner := &efsProvisioner{ + fileSystemID: fileSystemID, + mountPoint: mountPoint, + subPath: subPath, + allocator: gidallocator.New(clientset), + } + + pc := controller.NewProvisionController( + clientset, + provisionerName, + efsProvisioner, + serverVersion.GitVersion, + ) + + pc.Run(wait.NeverStop) +} diff --git a/aws-efs-csi-pv-provisioner_test.go b/aws-efs-csi-pv-provisioner_test.go new file mode 100644 index 0000000..b98635b --- /dev/null +++ b/aws-efs-csi-pv-provisioner_test.go @@ -0,0 +1,142 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "testing" + + v1 "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1" + storageapis "k8s.io/api/storage/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/sig-storage-lib-external-provisioner/controller" + "sigs.k8s.io/sig-storage-lib-external-provisioner/gidallocator" + + "k8s.io/client-go/kubernetes/fake" + + "github.com/stretchr/testify/assert" +) + +var fakeClient = fake.NewSimpleClientset() +var provisioner = efsProvisioner{ + fileSystemID: "fs-123456", + mountPoint: "./efs", + subPath: "/persistentvolumes", + allocator: gidallocator.New(fakeClient), +} + +var sc = &storage.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: "efs-sc", + }, +} + +func TestMain(m *testing.M) { + dir, err := ioutil.TempDir("/tmp", "chroot-test") + if err != nil { + log.Fatal("failed to create temporary directory: ", err) + } + os.Chdir(dir) + + fakeClient.StorageV1().StorageClasses().Create(sc) + + defer os.RemoveAll(dir) + os.Exit(m.Run()) +} + +func TestProvisionAndDelete(t *testing.T) { + const pvName = "pvc-123456" + + mountOptions := []string{"something", "something-else"} + retain := v1.PersistentVolumeReclaimRetain + + options := controller.ProvisionOptions{ + StorageClass: &storageapis.StorageClass{ + ReclaimPolicy: &retain, + Parameters: map[string]string{ + "gidallocate": "false", // don't test gid allocation + }, + MountOptions: mountOptions, + }, + PVName: pvName, + PVC: &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pvc", + Namespace: "my-ns", + }, + Spec: v1.PersistentVolumeClaimSpec{ + AccessModes: []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}, + Resources: v1.ResourceRequirements{ + Requests: v1.ResourceList{ + v1.ResourceName(v1.ResourceStorage): resource.Quantity{Format: "1Mi"}, + }, + }, + }, + }, + SelectedNode: &v1.Node{}, + } + + pv, err := provisioner.Provision(options) + + fakeClient.CoreV1().PersistentVolumes().Create(pv) + + assert.NoError(t, err, "Provision() failed") + assert.Equal(t, pvName, pv.Name, "Name is not copied") + assert.Equal(t, retain, pv.Spec.PersistentVolumeReclaimPolicy, "Reclaim policy is not copied") + assert.Equal(t, []v1.PersistentVolumeAccessMode{v1.ReadWriteMany}, pv.Spec.AccessModes, "Access modes are not copied") + assert.Equal(t, resource.Quantity{Format: "1Mi"}, pv.Spec.Capacity[v1.ResourceName(v1.ResourceStorage)], "Capacity is not copied") + assert.Equal(t, "efs-sc", pv.Spec.StorageClassName, "Incorrect storage class name") + assert.Equal(t, mountOptions, pv.Spec.MountOptions, "Mount options are not copied") + assert.Equal(t, efsCsiDriverName, pv.Spec.PersistentVolumeSource.CSI.Driver, "Driver name in PV is incorrect") + assert.Equal(t, "fs-123456:/persistentvolumes/my-ns-my-pvc-pvc-123456", pv.Spec.PersistentVolumeSource.CSI.VolumeHandle) + + stat, err := os.Stat("./efs/persistentvolumes/my-ns-my-pvc-pvc-123456") + assert.NoError(t, err, "os.Stat() failed: directory for PV probably doesn't exit") + assert.True(t, stat.IsDir(), "Is not a directory") + + err = provisioner.Delete(pv) + assert.NoError(t, err, "Delete() failed") + + _, err = os.Stat("./efs/persistentvolumes/my-ns-my-pvc-pvc-123456") + assert.Error(t, err, "Directory for PV was not deleted") + assert.True(t, os.IsNotExist(err), "error is not a NotExist error") + + _, err = os.Stat("./efs/persistentvolumes") + assert.NoError(t, err, "mountPoint/subPath was deleted") + assert.True(t, stat.IsDir(), "Is not a directory") +} + +func TestGetLocalPathToDelete(t *testing.T) { + _, err := provisioner.getLocalPathToDelete(&v1.CSIPersistentVolumeSource{ + Driver: "efs.something", + VolumeHandle: "fs-123456", + }) + assert.Error(t, err, "Wrong driver string is ignored") + + for _, fsID := range []string{ + "fs-12345", + "fs-123456:", + "fs-123456:/", + "fs-123456:/persistentvolumes", + "fs-123456:/persistentvolumes/", + "fs-123456:/persistentvolumes/..", + "fs-123456:/persistentvolumes/../", + } { + _, err = provisioner.getLocalPathToDelete(&v1.CSIPersistentVolumeSource{ + Driver: efsCsiDriverName, + VolumeHandle: fsID, + }) + assert.Error(t, err, "Wrong filesystem ID string is ignored: %s", fsID) + fmt.Println(err) + } + + path, err := provisioner.getLocalPathToDelete(&v1.CSIPersistentVolumeSource{ + Driver: efsCsiDriverName, + VolumeHandle: "fs-123456:/persistentvolumes/something", + }) + assert.NoError(t, err) + assert.Equal(t, "efs/persistentvolumes/something", path) +} diff --git a/deploy/deployment.yaml b/deploy/deployment.yaml new file mode 100644 index 0000000..d4af4e8 --- /dev/null +++ b/deploy/deployment.yaml @@ -0,0 +1,27 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: aws-efs-csi-pv-provisioner +spec: + replicas: 1 + selector: + matchLabels: + app: aws-efs-csi-pv-provisioner + template: + metadata: + labels: + app: aws-efs-csi-pv-provisioner + spec: + serviceAccountName: aws-efs-csi-pv-provisioner + containers: + - name: aws-efs-csi-pv-provisioner + image: # put image here + args: + - -file-system-id=fs-12345678 # change FS ID here + volumeMounts: + - mountPath: /efs + name: efs + volumes: + - name: efs + persistentVolumeClaim: + claimName: aws-efs-csi-pv-provisioner-root diff --git a/deploy/pv.yaml b/deploy/pv.yaml new file mode 100644 index 0000000..a4fa2ec --- /dev/null +++ b/deploy/pv.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: aws-efs-csi-pv-provisioner-root +spec: + capacity: + storage: 1Mi + volumeMode: Filesystem + accessModes: + - ReadWriteMany + mountOptions: + - tls + - iam + persistentVolumeReclaimPolicy: Retain + storageClassName: efs-sc + csi: + driver: efs.csi.aws.com + volumeHandle: fs-12345678:/ # change FS ID here diff --git a/deploy/pvc.yaml b/deploy/pvc.yaml new file mode 100644 index 0000000..d8a503f --- /dev/null +++ b/deploy/pvc.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: aws-efs-csi-pv-provisioner-root +spec: + accessModes: + - ReadWriteMany + storageClassName: efs-sc + resources: + requests: + storage: 1Mi diff --git a/deploy/rbac.yaml b/deploy/rbac.yaml new file mode 100644 index 0000000..6ab3e0f --- /dev/null +++ b/deploy/rbac.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: aws-efs-csi-pv-provisioner +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: aws-efs-csi-pv-provisioner +rules: +- apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "create", "delete"] +- apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "update"] +- apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["events"] + verbs: ["create", "update", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: aws-efs-csi-pv-provisioner +subjects: +- kind: ServiceAccount + name: aws-efs-csi-pv-provisioner + namespace: kube-system +roleRef: + kind: ClusterRole + name: aws-efs-csi-pv-provisioner + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: aws-efs-csi-pv-provisioner +rules: +- apiGroups: [""] + resources: ["endpoints"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aws-efs-csi-pv-provisioner +subjects: +- kind: ServiceAccount + name: aws-efs-csi-pv-provisioner +roleRef: + kind: Role + name: aws-efs-csi-pv-provisioner + apiGroup: rbac.authorization.k8s.io diff --git a/deploy/sc.yaml b/deploy/sc.yaml new file mode 100644 index 0000000..9d98fa7 --- /dev/null +++ b/deploy/sc.yaml @@ -0,0 +1,8 @@ +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: efs +provisioner: aws.k8s.logmein.com/efs-csi-pv-provisioner +mountOptions: +- tls +- iam diff --git a/docs/overview.drawio b/docs/overview.drawio new file mode 100644 index 0000000..e029965 --- /dev/null +++ b/docs/overview.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/docs/overview.svg b/docs/overview.svg new file mode 100644 index 0000000..42f020e --- /dev/null +++ b/docs/overview.svg @@ -0,0 +1,3 @@ + + +
subdirectory on EFS:
/persistentvolumes/<namespace>-<PVC name>-<PV name>
subdirectory on EFS:...
EFS
EFS
Node
Node
aws-efs-csi-driver
aws-efs-csi-driver
Control plane / addon workers
Control plane / addon workers
aws-efs-csi-pv-provisioner
aws-efs-csi-pv-provisioner
aws-efs-csi-pv-provisioner
aws-efs-csi-pv-provisioner
mounted into
mounted into
mounted into
mounted into
creates
creates
StorageClass "efs"
StorageClass...
PVC





StorageClass:
"efs"
PVC...
refers to
refers to
binds to
binds to
reacts on
reacts on
aws-efs-csi-driver
aws-efs-csi-driver
PV





CSI Driver:
"efs.csi.aws.com"
PV...
1
1
3
3
4
4
2
2
creates
creates
1
1
5
5
refer to
refer to
application pod
application pod
reacts on
reacts on
creates PV and
binds it to PVC

with subdirectory
configured
creates PV and...
creates subdirectory for PVC
creates subdirectory for PVC
performs the mount
performs the mount
application pod
application pod
mounts root directory of EFS into
container for management operations
mounts root directory of EFS into...
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..193f4cb --- /dev/null +++ b/go.mod @@ -0,0 +1,18 @@ +module aws.k8s.logmein.com/efs-csi-pv-provisioner + +go 1.12 + +require ( + github.com/aws/aws-sdk-go v1.25.8 + github.com/miekg/dns v1.1.22 // indirect + github.com/prometheus/client_golang v1.1.0 // indirect + github.com/stretchr/testify v1.3.0 + golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc // indirect + golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 // indirect + k8s.io/api v0.0.0-20191003000013-35e20aa79eb8 + k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 + k8s.io/client-go v0.0.0-20191003000419-f68efa97b39e + k8s.io/klog v1.0.0 + k8s.io/utils v0.0.0-20190923111123-69764acb6e8e // indirect + sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.1+incompatible +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3958e5a --- /dev/null +++ b/go.sum @@ -0,0 +1,248 @@ +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= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aws/aws-sdk-go v1.25.8 h1:n7I+HUUXjun2CsX7JK+1hpRIkZrlKhd3nayeb+Xmavs= +github.com/aws/aws-sdk-go v1.25.8/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.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-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/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/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +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 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/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 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.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/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/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/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/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/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.22 h1:Jm64b3bO9kP43ddLjL2EY3Io6bmy1qGb9Xxz6TqS6rc= +github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/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/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.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +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/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +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/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +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-20181114220301-adae6a3d119a/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-20190613194153-d28f0bde5980/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-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +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 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w= +golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +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/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/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= +gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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= +k8s.io/api v0.0.0-20191003000013-35e20aa79eb8 h1:cJZ/+fVFIFQDkUewZeim5OhZ8X+h48lMtMsZgQMdxOo= +k8s.io/api v0.0.0-20191003000013-35e20aa79eb8/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= +k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 h1:CS1tBQz3HOXiseWZu6ZicKX361CZLT97UFnnPx0aqBw= +k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= +k8s.io/client-go v0.0.0-20191003000419-f68efa97b39e h1:S7/BObCpTSVf9vlBdEs5hKNzLCq5FMha6bbmRoDGROU= +k8s.io/client-go v0.0.0-20191003000419-f68efa97b39e/go.mod h1:UBFA5lo8nEOepaxS9koNccX/38rYMI3pa1EA1gaFZNg= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +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/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ= +k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20190923111123-69764acb6e8e h1:BXSmdH6S3YGLlhC89DZp+sNdYSmwNeDU6Xu5ZpzGOlM= +k8s.io/utils v0.0.0-20190923111123-69764acb6e8e/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.1+incompatible h1:Wc09EvmeiMCZf7UlasU0W2Rn4GVX/b+Lus4UwmUBvD4= +sigs.k8s.io/sig-storage-lib-external-provisioner v4.0.1+incompatible/go.mod h1:qhqLyNwJC49PoUalmtzYb4s9fT8HOMBTLbTY1QoVOqI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=