From 903b4f82fe549caceb08274c27ded030c625e7fd Mon Sep 17 00:00:00 2001 From: Alexander Matyushentsev Date: Thu, 6 Feb 2020 16:11:01 -0800 Subject: [PATCH] Integrate GitOps Engine into Flux --- cmd/fluxd/main.go | 46 +- go.mod | 34 +- go.sum | 372 ++++++++-- pkg/cluster/kubernetes/cached_disco.go | 110 --- pkg/cluster/kubernetes/cached_disco_test.go | 93 --- pkg/cluster/kubernetes/images.go | 56 +- pkg/cluster/kubernetes/kubernetes.go | 322 ++++----- pkg/cluster/kubernetes/kubernetes_test.go | 68 -- pkg/cluster/kubernetes/manifests_test.go | 26 +- pkg/cluster/kubernetes/namespacer.go | 41 +- pkg/cluster/kubernetes/namespacer_test.go | 53 +- pkg/cluster/kubernetes/resourcekinds.go | 189 ++---- pkg/cluster/kubernetes/sync.go | 588 +++------------- pkg/cluster/kubernetes/sync_test.go | 710 +------------------- 14 files changed, 764 insertions(+), 1944 deletions(-) delete mode 100644 pkg/cluster/kubernetes/cached_disco.go delete mode 100644 pkg/cluster/kubernetes/cached_disco_test.go delete mode 100644 pkg/cluster/kubernetes/kubernetes_test.go diff --git a/cmd/fluxd/main.go b/cmd/fluxd/main.go index 4916e99e5..eec9d838d 100644 --- a/cmd/fluxd/main.go +++ b/cmd/fluxd/main.go @@ -18,13 +18,12 @@ import ( "syscall" "time" + "github.com/argoproj/argo-cd/engine/pkg/utils/io" "github.com/go-kit/kit/log" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/spf13/pflag" - crd "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" k8serrors "k8s.io/apimachinery/pkg/api/errors" k8sruntime "k8s.io/apimachinery/pkg/util/runtime" - k8sclientdynamic "k8s.io/client-go/dynamic" k8sclient "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -404,6 +403,8 @@ func main() { }() // Cluster component. + fileinfo, err := os.Stat(k8sInClusterSecretsBaseDir) + isInCluster := err == nil && fileinfo.IsDir() var restClientConfig *rest.Config { @@ -436,11 +437,6 @@ func main() { logger.Log("err", err) os.Exit(1) } - dynamicClientset, err := k8sclientdynamic.NewForConfig(restClientConfig) - if err != nil { - logger.Log("err", err) - os.Exit(1) - } fhrClientset, err := hrclient.NewForConfig(restClientConfig) if err != nil { @@ -454,13 +450,6 @@ func main() { os.Exit(1) } - crdClient, err := crd.NewForConfig(restClientConfig) - if err != nil { - logger.Log("error", fmt.Sprintf("Error building API extensions (CRD) clientset: %v", err)) - os.Exit(1) - } - discoClientset := kubernetes.MakeCachedDiscovery(clientset.Discovery(), crdClient, shutdown) - serverVersion, err := clientset.ServerVersion() if err != nil { logger.Log("err", err) @@ -468,8 +457,6 @@ func main() { } clusterVersion = "kubernetes-" + serverVersion.GitVersion - fileinfo, err := os.Stat(k8sInClusterSecretsBaseDir) - isInCluster := err == nil && fileinfo.IsDir() if isInCluster && !httpGitURL { namespace, err := ioutil.ReadFile(filepath.Join(k8sInClusterSecretsBaseDir, "serviceaccount/namespace")) if err != nil { @@ -502,6 +489,7 @@ func main() { logger.Log("host", restClientConfig.Host, "version", clusterVersion) + // FIXME: This is currently not honored by the GitOps Engine kubectl := *kubernetesKubectl if kubectl == "" { kubectl, err = exec.LookPath("kubectl") @@ -514,17 +502,22 @@ func main() { } logger.Log("kubectl", kubectl) - client := kubernetes.MakeClusterClientset(clientset, dynamicClientset, fhrClientset, hrClientset, discoClientset) - kubectlApplier := kubernetes.NewKubectl(kubectl, restClientConfig) - allowedNamespaces := make(map[string]struct{}) - for _, n := range append(*k8sNamespaceWhitelist, *k8sAllowNamespace...) { - allowedNamespaces[n] = struct{}{} - } - + client := kubernetes.MakeClusterClientset(clientset, fhrClientset, hrClientset) + allowedNamespaces := append(*k8sNamespaceWhitelist, *k8sAllowNamespace...) imageIncluder := cluster.ExcludeIncludeGlob{Exclude: *registryExcludeImage, Include: *registryIncludeImage} - k8sInst := kubernetes.NewCluster(client, kubectlApplier, sshKeyRing, logger, allowedNamespaces, imageIncluder, *k8sExcludeResource) + k8sInst, err := kubernetes.NewCluster(restClientConfig, *k8sDefaultNamespace, client, sshKeyRing, logger, allowedNamespaces, imageIncluder, *k8sExcludeResource) + if err != nil { + logger.Log("err", err) + os.Exit(1) + } k8sInst.GC = *syncGC k8sInst.DryGC = *dryGC + closer, err := k8sInst.Run() + if err != nil { + logger.Log("error", "Failed to initialize cluster", "err", err) + os.Exit(1) + } + defer io.Close(closer) if err := k8sInst.Ping(); err != nil { logger.Log("ping", err) @@ -536,15 +529,14 @@ func main() { imageCreds = k8sInst.ImagesToFetch // There is only one way we currently interpret a repo of // files as manifests, and that's as Kubernetes yamels. - namespacer, err := kubernetes.NewNamespacer(discoClientset, *k8sDefaultNamespace) if err != nil { logger.Log("err", err) os.Exit(1) } if *sopsEnabled { - k8sManifests = kubernetes.NewSopsManifests(namespacer, logger) + k8sManifests = kubernetes.NewSopsManifests(k8sInst.Namespacer(), logger) } else { - k8sManifests = kubernetes.NewManifests(namespacer, logger) + k8sManifests = kubernetes.NewManifests(k8sInst.Namespacer(), logger) } } diff --git a/go.mod b/go.mod index b1d8a82d9..16a97dd1f 100644 --- a/go.mod +++ b/go.mod @@ -15,13 +15,37 @@ replace ( github.com/fluxcd/helm-operator => github.com/fluxcd/helm-operator v1.0.0-rc6 ) +// to be removed after https://github.com/argoproj/argo-cd/pull/3066 is merged +replace ( + github.com/argoproj/argo-cd => github.com/argoproj/argo-cd v0.8.1-0.20200227223151-3cf5640c92f8 // gitops-engine branch + github.com/argoproj/argo-cd/engine => github.com/argoproj/argo-cd/engine v0.0.0-20200227223151-3cf5640c92f8 // gitops-engine branch +) + // Pin kubernetes dependencies to 1.16.2 replace ( k8s.io/api => k8s.io/api v0.0.0-20191016110408-35e52d86657a // kubernetes-1.16.2 k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65 // kubernetes-1.16.2 k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8 + + // To be removed, added by @alexmt to integrate with the gitops engine + k8s.io/apiserver => k8s.io/apiserver v0.16.6 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.16.6 k8s.io/client-go => k8s.io/client-go v0.0.0-20191016111102-bec269661e48 // kubernetes-1.16.2 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.16.6 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.16.6 k8s.io/code-generator => k8s.io/code-generator v0.16.5-beta.1 // kubernetes-1.16.2 + k8s.io/component-base => k8s.io/component-base v0.16.6 + k8s.io/cri-api => k8s.io/cri-api v0.16.6 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.16.6 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.16.6 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.16.6 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.16.6 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.16.6 + k8s.io/kubectl => k8s.io/kubectl v0.16.6 + k8s.io/kubelet => k8s.io/kubelet v0.16.6 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.16.6 + k8s.io/metrics => k8s.io/metrics v0.16.6 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.16.6 ) // github.com/fluxcd/flux/pkg/install lives in this very repository, so use that @@ -29,10 +53,10 @@ replace github.com/fluxcd/flux/pkg/install => ./pkg/install require ( github.com/Jeffail/gabs v1.4.0 - github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver/v3 v3.0.3 github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/VividCortex/gohistogram v1.0.0 // indirect + github.com/argoproj/argo-cd/engine v1.4.2 github.com/aws/aws-sdk-go v1.27.1 github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 github.com/cheggaaa/pb/v3 v3.0.2 @@ -52,9 +76,10 @@ require ( github.com/gorilla/websocket v1.4.0 github.com/imdario/mergo v0.3.8 github.com/justinbarrick/go-k8s-portforward v1.0.4-0.20190722134107-d79fe1b9d79d + github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect github.com/opencontainers/go-digest v1.0.0-rc1 github.com/opentracing/opentracing-go v1.1.0 // indirect - github.com/pkg/errors v0.8.1 + github.com/pkg/errors v0.9.1 github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942 github.com/prometheus/client_golang v1.2.1 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 @@ -69,13 +94,14 @@ require ( github.com/weaveworks/promrus v1.2.0 // indirect github.com/whilp/git-urls v0.0.0-20160530060445-31bac0d230fa github.com/xeipuuv/gojsonschema v1.1.0 + github.com/yudai/pp v2.0.1+incompatible // indirect go.mozilla.org/sops/v3 v3.5.0 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 golang.org/x/time v0.0.0-20191024005414-555d28b269f0 - gopkg.in/yaml.v2 v2.2.4 + gopkg.in/yaml.v2 v2.2.8 k8s.io/api v0.17.0 - k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65 + k8s.io/apiextensions-apiserver v0.16.6 k8s.io/apimachinery v0.17.0 k8s.io/client-go v11.0.0+incompatible k8s.io/helm v2.16.1+incompatible diff --git a/go.sum b/go.sum index 3190a3ad3..b787baa30 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= 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= @@ -7,9 +8,10 @@ contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJ contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= github.com/Azure/azure-sdk-for-go v31.2.0+incompatible h1:kZFnTLmdQYNGfakatSivKHUfUnDZhqNdchHD4oIhp5k= github.com/Azure/azure-sdk-for-go v31.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v32.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible h1:3D2O4g8AwDwyWkM1HpMFVux/ccQJmGJHXsE004Wsu1Q= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v12.2.0+incompatible h1:2Fxszbg492oAJrcvJlgyVaTqnQYRkxmEK6VPCLLVpBI= github.com/Azure/go-autorest v12.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= @@ -53,9 +55,11 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA= github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -73,30 +77,51 @@ github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcy github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/hcsshim v0.0.0-20190417211021-672e52e9209d/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= +github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= 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/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/argoproj/argo-cd v0.8.1-0.20200227223151-3cf5640c92f8 h1:3M4iVjC8njkRIQdDdFDGZkz+wlIyePIOib9ziCs1Mx4= +github.com/argoproj/argo-cd v0.8.1-0.20200227223151-3cf5640c92f8/go.mod h1:UPOPiF6Y1y/oTL3X1KcuLbu7ljD7f4+SIaXvlowBmhE= +github.com/argoproj/argo-cd/engine v0.0.0-20200227223151-3cf5640c92f8 h1:PsEx4HE4ovSVAUf1hP+Jdb7aSXmimfTnejQzDWGvbtE= +github.com/argoproj/argo-cd/engine v0.0.0-20200227223151-3cf5640c92f8/go.mod h1:o+1aYRCqhvmlWFXyw6Sp3zhxavrKETepkA2e1/sRbRg= +github.com/argoproj/pkg v0.0.0-20200102163130-2dd1f3f6b4de h1:i19Yd0ERYAHtR84jnB8vmTuizk2q4Qw4NuayfRja5/A= +github.com/argoproj/pkg v0.0.0-20200102163130-2dd1f3f6b4de/go.mod h1:2EZ44RG/CcgtPTwrRR0apOc7oU6UIw8GjCUJWZ8X3bM= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.19.11 h1:tqaTGER6Byw3QvsjGW0p018U2UOqaJPeJuzoaF7jjoQ= github.com/aws/aws-sdk-go v1.19.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -104,49 +129,71 @@ github.com/aws/aws-sdk-go v1.23.13 h1:l/NG+mgQFRGG3dsFzEj0jw9JIs/zYdtU6MXhY1WIDm github.com/aws/aws-sdk-go v1.23.13/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1 h1:MXnqY6SlWySaZAqNnXThOvjRFdiiOuKtC6i7baFdNdU= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/bazelbuild/bazel-gazelle v0.18.2/go.mod h1:D0ehMSbS+vesFsLGiD6JXu3mVEzOlfUl8wNnq+x/9p0= +github.com/bazelbuild/bazel-gazelle v0.19.1-0.20191105222053-70208cbdc798/go.mod h1:rPwzNHUqEzngx1iVBfO/2X2npKaT3tqPqqHW6rVsn/A= +github.com/bazelbuild/buildtools v0.0.0-20190731111112-f720930ceb60/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= +github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= +github.com/bazelbuild/rules_go v0.0.0-20190719190356-6dae44dc5cab/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= 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/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v1.5.0/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v1.5.3/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= +github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY= github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho= +github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheggaaa/pb/v3 v3.0.2 h1:/u+zw5RBzW1CxRpVIqrZv4PpZpN+yaRPdsRORKyDjv4= github.com/cheggaaa/pb/v3 v3.0.2/go.mod h1:SqqeMF/pMOIu3xgGoxtPYhMNQP258xE4x/XRTYua+KU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cloudflare/cfssl v0.0.0-20180726162950-56268a613adf/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= +github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= +github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= +github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0-beta.2.0.20190823190603-4a2f61c4f2b4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/coredns/corefile-migration v1.0.2/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 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-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/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/rkt v1.30.0/go.mod h1:O634mlH6U7qk87poQifK6M2rsFNt+FyUTWNMnP1hF1U= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= @@ -170,6 +217,7 @@ github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA= github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= @@ -178,6 +226,7 @@ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHz github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 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/libnetwork v0.0.0-20180830151422-a9cd636e3789/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= @@ -185,7 +234,6 @@ github.com/docker/spdystream v0.0.0-20170912183627-bc6354cbbc29/go.mod h1:Qh8CwZ github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/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/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= @@ -197,14 +245,21 @@ github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f h1:AUj1VoZUfhP github.com/elazarl/goproxy/ext v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= 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/emicklei/go-restful v2.11.1+incompatible h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE= github.com/emicklei/go-restful v2.11.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= github.com/evanphx/json-patch v4.1.0+incompatible h1:K1MDoo4AZ4wU0GIU/fPmtZg7VpzLjCxu+UwBD1FvwOc= github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= @@ -213,6 +268,8 @@ github.com/fluxcd/distribution v0.0.0-20190419185413-6c9727e5e5de/go.mod h1:ASaO github.com/fluxcd/flux v1.15.0/go.mod h1:eKTHFkxOIEQL23j5Uz+OY1NLcWDjppTPlsRlDol6JZk= github.com/fluxcd/helm-operator v1.0.0-rc6 h1:S78osvwNm/VRwKrCK0jfa5ciCXNm6XiIDCCcv/rnH18= github.com/fluxcd/helm-operator v1.0.0-rc6/go.mod h1:a3RbngauN4uJDi/sBBpk1JOCZNCCyjGps69J2uEC9J0= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= @@ -220,16 +277,24 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= +github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= +github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= +github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= 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-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -241,11 +306,13 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -257,7 +324,7 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nA github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= @@ -266,14 +333,30 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -299,6 +382,7 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 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= @@ -309,11 +393,31 @@ 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/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= +github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= +github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM= +github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= +github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.18.0/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg= +github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= +github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/cadvisor v0.34.0/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= 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= @@ -321,6 +425,8 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-containerregistry v0.0.0-20200121192426-b0ae1fc74a66 h1:0N9z7Z3YxnVmrLRbbqVdYimGzPPpx4YHKi1e75q5bm8= github.com/google/go-containerregistry v0.0.0-20200121192426-b0ae1fc74a66/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= +github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= @@ -334,6 +440,8 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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= @@ -358,22 +466,23 @@ github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gosuri/uitable v0.0.3/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/goware/prefixer v0.0.0-20160118172347-395022866408 h1:Y9iQJfEqnN3/Nce9cOegemcy/9Ai5k3huT6E80F3zaw= github.com/goware/prefixer v0.0.0-20160118172347-395022866408/go.mod h1:PE1ycukgRPJ7bJ9a1fdfQ9j8i/cEcRAoLZzbxYpNB/s= github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM= github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/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.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE= github.com/grpc-ecosystem/grpc-gateway v1.8.5/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-20180715044906-d6c0cd880357 h1:Rem2+U35z1QtPQc6r+WolF7yXiefXqDKyk+lN2pE164= github.com/hashicorp/errwrap v0.0.0-20180715044906-d6c0cd880357/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -392,9 +501,11 @@ github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 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/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= @@ -405,6 +516,8 @@ github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoI github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/heketi/heketi v9.0.1-0.20190917153846-c2e2a4ab7ab9+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= +github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c h1:kQWxfPIHVLbgLzphqk3QUflDy9QdksZR4ygR807bpy0= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -422,9 +535,15 @@ github.com/instrumenta/kubeval v0.0.0-20190804145309-805845b47dfc h1:2wBB02X45Lu github.com/instrumenta/kubeval v0.0.0-20190804145309-805845b47dfc/go.mod h1:bpiMYvNpVxWjdJsS0hDRu9TrobT5GfWCZwJseGUstxE= github.com/instrumenta/kubeval v0.0.0-20190918223246-8d013ec9fc56 h1:kKOrEaxR9KvCDdnQqjiBxbaeJg/goLvJvW0lno6aWm4= github.com/instrumenta/kubeval v0.0.0-20190918223246-8d013ec9fc56/go.mod h1:bpiMYvNpVxWjdJsS0hDRu9TrobT5GfWCZwJseGUstxE= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= 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/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -438,10 +557,22 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/justinbarrick/go-k8s-portforward v1.0.2/go.mod h1:klMOboLnC1/UlkyJnYFjcMcbOtwAcKop+LkIZ4r428o= github.com/justinbarrick/go-k8s-portforward v1.0.4-0.20190722134107-d79fe1b9d79d h1:xQ/ZtcWCKzWg5QbOhq6RFPvevl+IE580Vm0Vgxuw3xs= github.com/justinbarrick/go-k8s-portforward v1.0.4-0.20190722134107-d79fe1b9d79d/go.mod h1:GkvGI25j2iHpJVINl/hZC+sbf9IJ1XkY1MtjSh3Usuk= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= +github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 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 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= @@ -451,20 +582,35 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 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/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 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/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= +github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= +github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= +github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= +github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= +github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 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 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -475,23 +621,34 @@ github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= 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/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/mesos/mesos-go v0.0.9/go.mod h1:kPYCMQ9gsOXVAle1OsoY4I1+9kPu8GHkf88aV59fDr4= +github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= github.com/miekg/dns v0.0.0-20181005163659-0d29b283ac0f/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= +github.com/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= @@ -504,18 +661,24 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD 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/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mozilla-services/yaml v0.0.0-20191106225358-5c216288813c h1:yE1NxRAZA3wF0laDWECtOe2J0tFjSHUI6MXXbMif+QY= github.com/mozilla-services/yaml v0.0.0-20191106225358-5c216288813c/go.mod h1:Is/Ucts/yU/mWyGR8yELRoO46mejouKsJfQLAIfTR18= +github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= +github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= 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/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= 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/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833 h1:t4WWQ9I797y7QUgeEjeXnVb+oYuEDQc6gLvrZJTYo94= github.com/ncabatoff/go-seq v0.0.0-20180805175032-b08ef85ed833/go.mod h1:0CznHmXSjMEqs5Tezj/w2emQoM41wzYM9KpDKUHPYag= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 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.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= @@ -524,6 +687,7 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/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.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -535,21 +699,32 @@ github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVo github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 h1:yvQ/2Pupw60ON8TYEIGGTAI77yZsWYkiOeHFZWkwlCk= +github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9 h1:QsgXACQhd9QJhEmRumbsMQQvBtmdS0mafoVEBplWXEg= github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v0.0.0-20180724185102-c2dbbc24a979/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942 h1:A7GG7zcGjl3jqAqGPmcNjd/D9hzL95SuoOQAaFNdLU0= github.com/pkg/term v0.0.0-20190109203006-aa71e9d9e942/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -557,6 +732,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= @@ -588,44 +764,67 @@ github.com/prometheus/procfs v0.0.3 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURm github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= +github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/robfig/cron v1.1.0 h1:jk4/Hud3TTdcrJgUOBgsqrZBarcxl6ADIjSC2iniwLY= +github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd h1:ug7PpSOB5RBPK1Kg6qskGBoP3Vnj/aNYFTznWvlkGo0= github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/sirupsen/logrus v1.0.5/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 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 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/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 h1:N8Bg45zpk/UcpNGnfJt2y/3lRWASHNTUET8owPYCgYI= github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= +github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 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.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.0-20180820174524-ff0d02e85550/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v0.0.0-20180814060501-14d3d4c51834/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v0.0.0-20180821114517-d929dcbb1086/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -633,8 +832,12 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.1.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -646,15 +849,27 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= +github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/uber/jaeger-client-go v2.21.1+incompatible h1:oozboeZmWz+tyh3VZttJWlF3K73mHgbokieceqKccLo= github.com/uber/jaeger-client-go v2.21.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw= github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= +github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= -github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vmware/govmomi v0.20.1/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/weaveworks/common v0.0.0-20190410110702-87611edc252e h1:Y5z9Bu95l0laB3xOF3BT6LWkcR7VcRxN0n+nf2S72xA= github.com/weaveworks/common v0.0.0-20190410110702-87611edc252e/go.mod h1:pSm+0KR57BG3pvGoJWFXJSAC7+sEPewcvdt5StevL3A= github.com/weaveworks/go-checkpoint v0.0.0-20170503165305-ebbb8b0518ab h1:mW+hgchD9qUUBqnuaDBj7BkcpFPk/FxeFcUFI5lvvUw= @@ -663,6 +878,8 @@ github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZG github.com/weaveworks/promrus v1.2.0/go.mod h1:SaE82+OJ91yqjrE1rsvBWVzNZKcHYFtMUyS1+Ogs/KA= github.com/whilp/git-urls v0.0.0-20160530060445-31bac0d230fa h1:rW+Lu6281ed/4XGuVIa4/YebTRNvoUJlfJ44ktEVwZk= github.com/whilp/git-urls v0.0.0-20160530060445-31bac0d230fa/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= @@ -674,14 +891,19 @@ github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4m github.com/xenolf/lego v0.0.0-20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.6/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/gorelic v0.0.7/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.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a h1:N7VD+PwpJME2ZfQT8+ejxwA4Ow10IkGbU0MGf94ll8k= go.mozilla.org/gopgagent v0.0.0-20170926210634-4d7ea76ff71a/go.mod h1:YDKUvO0b//78PaaEro6CAPH6NqohCmL2Cwju5XI2HoE= go.mozilla.org/sops/v3 v3.5.0 h1:GpO9JRZhk6Kc+FVw5Q0vmnvDM6k956ZRh5tbG98T4XI= @@ -694,18 +916,22 @@ go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569 h1:nSQar3Y0E3VQF/VdZ8PTAilaXpER+d7ypdABCrpwMdg= go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190927031335-2835ba2e683f/go.mod h1:fYw7AShPAhGMdXqA9gRadk/CcMsvLlClpE5oBwnS3dM= +golang.org/x/crypto v0.0.0-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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= @@ -735,10 +961,13 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20170915142106-8351a756f30f/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-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -748,8 +977,10 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r 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-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190328230028-74de082e2cca/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-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 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= @@ -758,15 +989,16 @@ golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-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-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/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-20190402181905-9f3314589c9a/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/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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= @@ -774,7 +1006,10 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180821044426-4ea2f632f6e9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -784,28 +1019,36 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190122071731-054c452bb702/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/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-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/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-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/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-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/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-20190626221950-04f50cda93cb/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 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 h1:u/E0NqCIWRDAo9WCFo6Ko49njPFDLSd3z+X1HgWDMpE= golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20180810153555-6e3c4e7365dd/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 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= @@ -819,21 +1062,30 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZe golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-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-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/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-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190122202912-9c309ee22fab/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/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-20190311215038-5c2858a9cfe5/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-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= 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-20190521203540-521d6ed310dd/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= @@ -841,6 +1093,9 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0 h1:Dh6fw+p6FyRl5x/FvNswO1ji0lIGzm3KP8Y9VkS9PTE= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/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-20200115165105-de0b1760071a h1:bEJ3JL2YUH3tt9KX9dsy0WUF3WOrhjtNjK93o0svepY= golang.org/x/tools v0.0.0-20200115165105-de0b1760071a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -891,48 +1146,65 @@ google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 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 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +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/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.44.0 h1:YRJzTUp0kSYWUVFF5XAbDFfyiqwsl0Vb9R8TVP5eRi0= gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= 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.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA= 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/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= +gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= +gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 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 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= helm.sh/helm/v3 v3.0.2/go.mod h1:KBxE6XWO57XSNA1PA9CvVLYRY0zWqYQTad84bNXp1lw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= k8s.io/api v0.0.0-20191016110408-35e52d86657a h1:VVUE9xTCXP6KUPMf92cQmN88orz600ebexcRRaBTepQ= k8s.io/api v0.0.0-20191016110408-35e52d86657a/go.mod h1:/L5qH+AD540e7Cetbui1tuJeXdmNhO8jM6VkXeDdDhQ= @@ -940,20 +1212,24 @@ k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65 h1:kThoiqgMsSw k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65/go.mod h1:5BINdGqggRXXKnDgpwoJ7PyQH8f+Ypp02fvVNcIFy9s= k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8 h1:Iieh/ZEgT3BWwbLD5qEKcY06jKuPEl6zC7gPSehoLw4= k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= -k8s.io/apiserver v0.0.0-20191016112112-5190913f932d/go.mod h1:7OqfAolfWxUM/jJ/HBLyE+cdaWFBUoo5Q5pHgJVj2ws= -k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= -k8s.io/cli-runtime v0.0.0-20191016114015-74ad18325ed5/go.mod h1:sDl6WKSQkDM6zS1u9F49a0VooQ3ycYFBFLqd2jf2Xfo= +k8s.io/apiserver v0.16.6 h1:7woiO69qcmhmTv2lsgAux2nb3bekuyogl3wzRI2HOBA= +k8s.io/apiserver v0.16.6/go.mod h1:JaDblfPzg2nbxaA0H3PsMgO72QAx2rBoSYwxLEKu5RE= +k8s.io/cli-runtime v0.16.6 h1:Z0X6rJanDHrpPtpJG3ObfRuPtlhvrJOJsfdqL+Y7bnw= +k8s.io/cli-runtime v0.16.6/go.mod h1:8N6G/UJmYvLXzpD1kjpuss6mFUeez+eg6Nu15VtBHvM= k8s.io/client-go v0.0.0-20191016111102-bec269661e48 h1:C2XVy2z0dV94q9hSSoCuTPp1KOG7IegvbdXuz9VGxoU= k8s.io/client-go v0.0.0-20191016111102-bec269661e48/go.mod h1:hrwktSwYGI4JK+TJA3dMaFyyvHVi/aLarVHpbs8bgCU= -k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/cloud-provider v0.16.6/go.mod h1:rTwoMb7ogSqEAZWev8ds88EApSPC6vVAikKgpvjOxpE= +k8s.io/cluster-bootstrap v0.16.6/go.mod h1:cOnd4cgo8AthVSyH7rIWpUNUdJyuCthsZjA2MEsFipI= k8s.io/code-generator v0.16.5-beta.1 h1:+zWxMQH3a6fd8lZe6utWyW/V7nmG2ZMXwtovSJI2p+0= k8s.io/code-generator v0.16.5-beta.1/go.mod h1:mJUgkl06XV4kstAnLHAIzJPVCOzVR+ZcfPIv4fUsFCY= -k8s.io/component-base v0.0.0-20191016111319-039242c015a9/go.mod h1:SuWowIgd/dtU/m/iv8OD9eOxp3QZBBhTIiWMsBQvKjI= -k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= -k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/component-base v0.16.6 h1:1qIWVKni+gqRkN8vvaGYJk+R8tRtKDv0XvvDuYEBD1w= +k8s.io/component-base v0.16.6/go.mod h1:8+4lrSEgLQ9wqOzHVYx4GLSCU6sus8wqg8bfaTdXTwg= +k8s.io/cri-api v0.16.6/go.mod h1:W6aMMPN5fmxcRGaHnb6BEfoTeS82OsJcsUJyKf+EWYc= +k8s.io/csi-translation-lib v0.16.6/go.mod h1:T/bEjsu1sQn2qVi9FzsPqjvT31mSqpThoFwtnj327jg= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505 h1:ZY6yclUKVbZ+SdWnkfY+Je5vrMpKOxmGeKRbsXVmqYM= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= k8s.io/helm v2.13.1+incompatible h1:qt0LBsHQ7uxCtS3F2r3XI0DNm8ml0xQeSJixUorDyn0= k8s.io/helm v2.13.1+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= k8s.io/helm v2.16.1+incompatible h1:L+k810plJlaGWEw1EszeT4deK8XVaKxac1oGcuB+WDc= @@ -965,32 +1241,44 @@ k8s.io/klog v0.3.3/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-aggregator v0.16.6 h1:bNwY/t432BgxoL73jEMD5EdZQCUkqw5kwhQxFmxdNss= +k8s.io/kube-aggregator v0.16.6/go.mod h1:lRjo9e3xeyF8tjkIKEX+pErNOdE4yTazx9VPO6zzdcw= +k8s.io/kube-controller-manager v0.16.6/go.mod h1:7ovDaVMCHc4TBOQHzfb5w2XCib7rjx+QCMZTRVQteD4= k8s.io/kube-openapi v0.0.0-20180509051136-39cb288412c4/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d h1:Xpe6sK+RY4ZgCTyZ3y273UmFmURhjtoJiwOMbQsXitY= k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51/go.mod h1:gL826ZTIfD4vXTGlmzgTbliCAT9NGiqpCqK2aNYv5MQ= -k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= -k8s.io/metrics v0.0.0-20191016113814-3b1a734dba6e/go.mod h1:ve7/vMWeY5lEBkZf6Bt5TTbGS3b8wAxwGbdXAsufjRs= +k8s.io/kube-proxy v0.16.6/go.mod h1:l7jgZcYyjERYxALU/EizkMx/JmIhN2Ff/f/aR/azFKg= +k8s.io/kube-scheduler v0.16.6/go.mod h1:ohT2kmuQnNex0cDUYvXBAdMKHlneruoD4KOacEDpPq4= +k8s.io/kubectl v0.16.6 h1:u7bQl9F78+7wYcvBSX7JfnIotLIQfAVpN1E11m2s+3w= +k8s.io/kubectl v0.16.6/go.mod h1:ybKdxxoYuQLRqsmBFylvgyFPeVmmRYUbxk134JCiNoM= +k8s.io/kubelet v0.16.6/go.mod h1:NAuB1uZwiOgUnJSgAnJIkWlueXFYkzxwv7xWEA/P35Y= +k8s.io/kubernetes v1.16.6 h1:ZWSNwxZ1w/IPV7pYH9gohR7AhKmn1VoJ9fEKxmkkeh8= +k8s.io/kubernetes v1.16.6/go.mod h1:rO6tSgbJjbo6lLkrq4jryUaXqZ2PdDJjzWXKZQmLfnQ= +k8s.io/legacy-cloud-providers v0.16.6/go.mod h1:trzyJ8vT+vD+FEP4NHDbJvOXYtksUbpD7PfR6Iwnhxk= +k8s.io/metrics v0.16.6/go.mod h1:de0nJbsn2wX/fapLW0Yi7k+GwXvEv4/g54agaDjzmQY= +k8s.io/repo-infra v0.0.1-alpha.1/go.mod h1:wO1t9WaB99V80ljbeENTnayuEEwNZt7gECYh/CEyOJ8= +k8s.io/sample-apiserver v0.16.6/go.mod h1:fyN8DaZXgtcQKCtb/x2mr4TDTUkaAdgWNU7BaLnlSqg= k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA= k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/letsencrypt v0.0.1/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff v1.0.1/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= +vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/pkg/cluster/kubernetes/cached_disco.go b/pkg/cluster/kubernetes/cached_disco.go deleted file mode 100644 index 21963d029..000000000 --- a/pkg/cluster/kubernetes/cached_disco.go +++ /dev/null @@ -1,110 +0,0 @@ -package kubernetes - -import ( - "fmt" - "sync" - "time" - - crdv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - crd "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - "k8s.io/client-go/discovery/cached/memory" - toolscache "k8s.io/client-go/tools/cache" -) - -// This exists so that we can do our own invalidation. -type cachedDiscovery struct { - discovery.CachedDiscoveryInterface - - invalidMu sync.Mutex - invalid bool -} - -// The k8s.io/client-go v8.0.0 implementation of MemCacheDiscovery -// refreshes the cached values, synchronously, when Invalidate() is -// called. Since we want to invalidate every time a CRD changes, but -// only refresh values when we need to read the cached values, this -// method defers the invalidation until a read is done. -func (d *cachedDiscovery) Invalidate() { - d.invalidMu.Lock() - d.invalid = true - d.invalidMu.Unlock() -} - -// ServerResourcesForGroupVersion is the method used by the -// namespacer; so, this is the one where we check whether the cache -// has been invalidated. A cachedDiscovery implementation for more -// general use would do this for all methods (that weren't implemented -// purely in terms of other methods). -func (d *cachedDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) { - d.invalidMu.Lock() - invalid := d.invalid - d.invalid = false - d.invalidMu.Unlock() - if invalid { - d.CachedDiscoveryInterface.Invalidate() - } - result, err := d.CachedDiscoveryInterface.ServerResourcesForGroupVersion(groupVersion) - if err == memory.ErrCacheNotFound { - // improve the error returned from memcacheclient - err = fmt.Errorf("server resources for %s not found in cache; cache refreshes every 5 minutes", groupVersion) - } - return result, err -} - -// MakeCachedDiscovery constructs a CachedDicoveryInterface that will -// be invalidated whenever the set of CRDs change. The idea is that -// the only avenue of a change to the API resources in a running -// system is CRDs being added, updated or deleted. -func MakeCachedDiscovery(d discovery.DiscoveryInterface, c crd.Interface, shutdown <-chan struct{}) discovery.CachedDiscoveryInterface { - cachedDisco := &cachedDiscovery{CachedDiscoveryInterface: memory.NewMemCacheClient(d)} - // We have an empty cache, so it's _a priori_ invalid. (Yes, that's the zero value, but better safe than sorry) - cachedDisco.Invalidate() - - crdClient := c.ApiextensionsV1beta1().CustomResourceDefinitions() - lw := &toolscache.ListWatch{ - ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - return crdClient.List(options) - }, - WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return crdClient.Watch(options) - }, - } - handle := toolscache.ResourceEventHandlerFuncs{ - AddFunc: func(_ interface{}) { - cachedDisco.Invalidate() - }, - UpdateFunc: func(_, _ interface{}) { - cachedDisco.Invalidate() - }, - DeleteFunc: func(_ interface{}) { - cachedDisco.Invalidate() - }, - } - _, controller := toolscache.NewInformer(lw, &crdv1beta1.CustomResourceDefinition{}, 0, handle) - go cachedDisco.invalidatePeriodically(shutdown) - go controller.Run(shutdown) - return cachedDisco -} - -func (d *cachedDiscovery) invalidatePeriodically(shutdown <-chan struct{}) { - // Make the first period shorter since we may be bootstrapping a - // newly-created cluster and the resource definitions may not be - // complete/stable yet. - initialPeriodDuration := 1 * time.Minute - subsequentPeriodsDuration := 5 * initialPeriodDuration - timer := time.NewTimer(initialPeriodDuration) - for { - select { - case <-timer.C: - timer.Reset(subsequentPeriodsDuration) - d.Invalidate() - case <-shutdown: - timer.Stop() - return - } - } -} diff --git a/pkg/cluster/kubernetes/cached_disco_test.go b/pkg/cluster/kubernetes/cached_disco_test.go deleted file mode 100644 index 0e6e71ef8..000000000 --- a/pkg/cluster/kubernetes/cached_disco_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package kubernetes - -import ( - "testing" - "time" - - "github.com/stretchr/testify/assert" - crdv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" - crdfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func TestCachedDiscovery(t *testing.T) { - coreClient := makeFakeClient() - - myCRD := &crdv1beta1.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: "custom", - }, - } - crdClient := crdfake.NewSimpleClientset(myCRD) - - // Here's my fake API resource - myAPI := &metav1.APIResourceList{ - GroupVersion: "foo/v1", - APIResources: []metav1.APIResource{ - {Name: "customs", SingularName: "custom", Namespaced: true, Kind: "Custom", Verbs: getAndList}, - }, - } - - apiResources := coreClient.Fake.Resources - coreClient.Fake.Resources = append(apiResources, myAPI) - - shutdown := make(chan struct{}) - defer close(shutdown) - - cachedDisco := MakeCachedDiscovery(coreClient.Discovery(), crdClient, shutdown) - - saved := getKubeconfigDefaultNamespace - getKubeconfigDefaultNamespace = func() (string, error) { return "bar-ns", nil } - defer func() { getKubeconfigDefaultNamespace = saved }() - namespacer, err := NewNamespacer(cachedDisco, "") - if err != nil { - t.Fatal(err) - } - - namespaced, err := namespacer.lookupNamespaced("foo/v1", "Custom", nil) - if err != nil { - t.Fatal(err) - } - if !namespaced { - t.Error("got false from lookupNamespaced, expecting true") - } - - // In a cluster, we'd rely on the apiextensions server to reflect - // changes to CRDs to changes in the API resources. Here I will be - // more narrow, and just test that the API resources are reloaded - // when a CRD is updated or deleted. - - // This is delicate: we can't just change the value in-place, - // since that will update everyone's record of it, and the test - // below will trivially succeed. - updatedAPI := &metav1.APIResourceList{ - GroupVersion: "foo/v1", - APIResources: []metav1.APIResource{ - {Name: "customs", SingularName: "custom", Namespaced: false /* <-- changed */, Kind: "Custom", Verbs: getAndList}, - }, - } - coreClient.Fake.Resources = append(apiResources, updatedAPI) - - // Provoke the cached discovery client into invalidating - _, err = crdClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(myCRD) - if err != nil { - t.Fatal(err) - } - - // Wait for the update to "go through" - c := time.After(time.Second) -loop: - for { - select { - default: - namespaced, err = namespacer.lookupNamespaced("foo/v1", "Custom", nil) - assert.NoError(t, err) - if !namespaced { - break loop - } - time.Sleep(10 * time.Millisecond) - case <-c: - t.Fatal("timed out waiting for Update to happen") - } - } -} diff --git a/pkg/cluster/kubernetes/images.go b/pkg/cluster/kubernetes/images.go index 4dc2f3c42..cf8942ea4 100644 --- a/pkg/cluster/kubernetes/images.go +++ b/pkg/cluster/kubernetes/images.go @@ -1,13 +1,11 @@ package kubernetes import ( - "context" "fmt" "github.com/go-kit/kit/log" "github.com/pkg/errors" apiv1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/fluxcd/flux/pkg/image" @@ -72,7 +70,8 @@ func mergeCredentials(log func(...interface{}) error, creds.Merge(seen) continue } - + // TODO: this, and the service account request above, are the only remaining direct accesses to the API server. + // We should probably cache service-account imagePullSecrets like we do with namespaces. secret, err := client.CoreV1().Secrets(namespace).Get(name, meta_v1.GetOptions{}) if err != nil { log("err", errors.Wrapf(err, "getting secret %q from namespace %q", name, namespace)) @@ -123,44 +122,31 @@ func mergeCredentials(log func(...interface{}) error, // ImagesToFetch is a k8s specific method to get a list of images to update along with their credentials func (c *Cluster) ImagesToFetch() registry.ImageCreds { allImageCreds := make(registry.ImageCreds) - ctx := context.Background() - namespaces, err := c.getAllowedAndExistingNamespaces(ctx) + imagePullSecretCache := make(map[string]registry.Credentials) + workloads, err := c.allWorkloads("") if err != nil { c.logger.Log("err", errors.Wrap(err, "getting namespaces")) return allImageCreds } - for _, ns := range namespaces { - imagePullSecretCache := make(map[string]registry.Credentials) // indexed by the namespace/name of pullImageSecrets - for kind, resourceKind := range resourceKinds { - workloads, err := resourceKind.getWorkloads(ctx, c, ns) - if err != nil { - if apierrors.IsNotFound(err) || apierrors.IsForbidden(err) { - // Skip unsupported or forbidden resource kinds - continue - } - c.logger.Log("err", errors.Wrapf(err, "getting kind %s for namespace %s", kind, ns)) - } - - imageCreds := make(registry.ImageCreds) - for _, workload := range workloads { - logger := log.With(c.logger, "resource", resource.MakeID(workload.GetNamespace(), kind, workload.GetName())) - mergeCredentials(logger.Log, c.imageIncluder.IsIncluded, c.client, workload.GetNamespace(), workload.podTemplate, imageCreds, imagePullSecretCache) - } - - // Merge creds - for imageID, creds := range imageCreds { - existingCreds, ok := allImageCreds[imageID] - if ok { - mergedCreds := registry.NoCredentials() - mergedCreds.Merge(existingCreds) - mergedCreds.Merge(creds) - allImageCreds[imageID] = mergedCreds - } else { - allImageCreds[imageID] = creds - } - } + imageCreds := make(registry.ImageCreds) + for id, workload := range workloads { + ns, kind, _ := id.Components() + logger := log.With(c.logger, "resource", resource.MakeID(ns, kind, workload.GetName())) + mergeCredentials(logger.Log, c.imageIncluder.IsIncluded, c.client, ns, workload.podTemplate, imageCreds, imagePullSecretCache) + } + + // Merge creds + for imageID, creds := range imageCreds { + existingCreds, ok := allImageCreds[imageID] + if ok { + mergedCreds := registry.NoCredentials() + mergedCreds.Merge(existingCreds) + mergedCreds.Merge(creds) + allImageCreds[imageID] = mergedCreds + } else { + allImageCreds[imageID] = creds } } diff --git a/pkg/cluster/kubernetes/kubernetes.go b/pkg/cluster/kubernetes/kubernetes.go index 76bfe0078..571c9dfc8 100644 --- a/pkg/cluster/kubernetes/kubernetes.go +++ b/pkg/cluster/kubernetes/kubernetes.go @@ -5,17 +5,24 @@ import ( "context" "encoding/json" "fmt" + "io" + "strings" "sync" + "github.com/argoproj/argo-cd/engine/pkg/engine" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube/cache" hrclient "github.com/fluxcd/helm-operator/pkg/client/clientset/versioned" "github.com/go-kit/kit/log" "github.com/pkg/errors" + "github.com/ryanuber/go-glob" "gopkg.in/yaml.v2" - apierrors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/discovery" - k8sclientdynamic "k8s.io/client-go/dynamic" k8sclient "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" fhrclient "github.com/fluxcd/flux/integrations/client/clientset/versioned" "github.com/fluxcd/flux/pkg/cluster" @@ -25,28 +32,22 @@ import ( ) type coreClient k8sclient.Interface -type dynamicClient k8sclientdynamic.Interface type fluxHelmClient fhrclient.Interface type helmOperatorClient hrclient.Interface type discoveryClient discovery.DiscoveryInterface type ExtendedClient struct { coreClient - dynamicClient fluxHelmClient helmOperatorClient - discoveryClient } -func MakeClusterClientset(core coreClient, dyn dynamicClient, fluxhelm fluxHelmClient, - helmop helmOperatorClient, disco discoveryClient) ExtendedClient { +func MakeClusterClientset(core coreClient, fluxhelm fluxHelmClient, helmop helmOperatorClient) ExtendedClient { return ExtendedClient{ coreClient: core, - dynamicClient: dyn, fluxHelmClient: fluxhelm, helmOperatorClient: helmop, - discoveryClient: disco, } } @@ -94,8 +95,10 @@ type Cluster struct { // dry run garbage collection without syncing DryGC bool - client ExtendedClient - applier Applier + engine engine.GitOpsEngine + clusterCache cache.ClusterCache + client ExtendedClient + fallbackNamespace string version string // string response for the version command. logger log.Logger @@ -107,60 +110,146 @@ type Cluster struct { muSyncErrors sync.RWMutex allowedNamespaces map[string]struct{} - loggedAllowedNS map[string]bool // to keep track of whether we've logged a problem with seeing an allowed namespace - imageIncluder cluster.Includer - resourceExcludeList []string - mu sync.Mutex + imageIncluder cluster.Includer + + workloadsLock sync.RWMutex + workloadsById map[resource.ID]workload + + allowedAndExistingNamespacesLock sync.RWMutex + allowedAndExistingNamespacesByName map[string]v1.Namespace +} + +type resourceFilter struct { + exclude []string +} + +func (f *resourceFilter) IsExcludedResource(group, kind, _ string) bool { + fullName := fmt.Sprintf("%s/%s", group, kind) + for _, exp := range f.exclude { + if glob.Glob(exp, fullName) { + return true + } + } + return false } // NewCluster returns a usable cluster. -func NewCluster(client ExtendedClient, applier Applier, sshKeyRing ssh.KeyRing, logger log.Logger, allowedNamespaces map[string]struct{}, imageIncluder cluster.Includer, resourceExcludeList []string) *Cluster { - if imageIncluder == nil { - imageIncluder = cluster.AlwaysInclude +func NewCluster(config *rest.Config, defaultNamespace string, client ExtendedClient, sshKeyRing ssh.KeyRing, logger log.Logger, allowedNamespaces []string, imageIncluder cluster.Includer, resourceExcludeList []string) (*Cluster, error) { + fallbackNamespace, err := getFallbackNamespace(defaultNamespace) + if err != nil { + return nil, err } + cacheSettings := cache.Settings{ResourcesFilter: &resourceFilter{exclude: resourceExcludeList}} + // TODO: shouldn't the cache and engine have a Stop() method + clusterCache := cache.NewClusterCache(cacheSettings, config, allowedNamespaces, &kube.KubectlCmd{}) + allowedNamespacesSet := map[string]struct{}{} + for _, nsName := range allowedNamespaces { + allowedNamespacesSet[nsName] = struct{}{} + } c := &Cluster{ - client: client, - applier: applier, - logger: logger, - sshKeyRing: sshKeyRing, - allowedNamespaces: allowedNamespaces, - loggedAllowedNS: map[string]bool{}, - imageIncluder: imageIncluder, - resourceExcludeList: resourceExcludeList, + fallbackNamespace: fallbackNamespace, + engine: engine.NewEngine(config, clusterCache), + clusterCache: clusterCache, + client: client, + logger: logger, + sshKeyRing: sshKeyRing, + allowedNamespaces: allowedNamespacesSet, + imageIncluder: imageIncluder, + workloadsById: map[resource.ID]workload{}, + allowedAndExistingNamespacesByName: map[string]v1.Namespace{}, } + clusterCache.SetPopulateResourceInfoHandler(func(un *unstructured.Unstructured, isRoot bool) (info interface{}, cacheManifest bool) { + c.OnResourceUpdated(un) + labels := un.GetLabels() + if labels != nil { + _, ok := labels[gcMarkLabel] + return nil, ok + } + return nil, false + }) + _ = clusterCache.OnResourceUpdated(func(newRes *cache.Resource, oldRes *cache.Resource, namespaceResources map[kube.ResourceKey]*cache.Resource) { + if newRes == nil && oldRes != nil { + c.OnResourceRemoved(oldRes.ResourceKey()) + } + }) - return c + return c, nil +} + +func (c *Cluster) Namespacer() namespacer { + return &namespacerViaInfoProvider{fallbackNamespace: c.fallbackNamespace, infoProvider: c.clusterCache} } // --- cluster.Cluster +func (c *Cluster) Run() (io.Closer, error) { + return c.engine.Run() +} + +func (c *Cluster) OnResourceRemoved(key kube.ResourceKey) { + // remove workload + c.workloadsLock.Lock() + defer c.workloadsLock.Unlock() + delete(c.workloadsById, resource.MakeID(key.Namespace, key.Kind, key.Name)) + + // remove namespace + if key.Kind == "Namespace" && key.Group == "" { + c.allowedAndExistingNamespacesLock.Lock() + delete(c.allowedAndExistingNamespacesByName, key.Name) + c.allowedAndExistingNamespacesLock.Unlock() + } +} + +func (c *Cluster) OnResourceUpdated(un *unstructured.Unstructured) { + id := resource.MakeID(un.GetNamespace(), un.GetKind(), un.GetName()) + + // Update workload + if kind, ok := resourceKinds[strings.ToLower(un.GetKind())]; ok { + c.workloadsLock.Lock() + defer c.workloadsLock.Unlock() + w, err := kind.getWorkload(un) + if err != nil { + c.logger.Log("msg", "unable to get workflow", "kind", un.GetKind(), "err", err) + } else { + c.workloadsById[id] = w + } + } + + // Update namespace + namespace := v1.Namespace{} + if un.GetKind() == "Namespace" && un.GroupVersionKind().Group == "" { + if _, ok := c.allowedNamespaces[un.GetName()]; len(c.allowedNamespaces) == 0 || ok { + err := runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &namespace) + if err != nil { + c.logger.Log("msg", "unable to convert namespace", "err", err) + } else { + c.allowedAndExistingNamespacesLock.Lock() + c.allowedAndExistingNamespacesByName[namespace.Name] = namespace + c.allowedAndExistingNamespacesLock.Unlock() + } + } + } +} // SomeWorkloads returns the workloads named, missing out any that don't // exist in the cluster or aren't in an allowed namespace. // They do not necessarily have to be returned in the order requested. -func (c *Cluster) SomeWorkloads(ctx context.Context, ids []resource.ID) (res []cluster.Workload, err error) { +func (c *Cluster) SomeWorkloads(_ context.Context, ids []resource.ID) (res []cluster.Workload, err error) { + c.workloadsLock.RLock() + defer c.workloadsLock.RUnlock() + var workloads []cluster.Workload for _, id := range ids { if !c.IsAllowedResource(id) { continue } - ns, kind, name := id.Components() - resourceKind, ok := resourceKinds[kind] + workload, ok := c.workloadsById[id] if !ok { - c.logger.Log("warning", "automation of this resource kind is not supported", "resource", id) continue } - workload, err := resourceKind.getWorkload(ctx, c, ns, name) - if err != nil { - if apierrors.IsForbidden(err) || apierrors.IsNotFound(err) { - continue - } - return nil, err - } - if !isAddon(workload) { c.muSyncErrors.RLock() workload.syncError = c.syncErrors[id] @@ -171,66 +260,42 @@ func (c *Cluster) SomeWorkloads(ctx context.Context, ids []resource.ID) (res []c return workloads, nil } -// AllWorkloads returns all workloads in allowed namespaces matching the criteria; that is, in -// the namespace (or any namespace if that argument is empty) -func (c *Cluster) AllWorkloads(ctx context.Context, restrictToNamespace string) (res []cluster.Workload, err error) { - allowedNamespaces, err := c.getAllowedAndExistingNamespaces(ctx) - if err != nil { - return nil, errors.Wrap(err, "getting namespaces") - } - // Those are the allowed namespaces (possibly just []; - // now intersect with the restriction requested, if any. - namespaces := allowedNamespaces - if restrictToNamespace != "" { - namespaces = nil - for _, ns := range allowedNamespaces { - if ns == meta_v1.NamespaceAll || ns == restrictToNamespace { - namespaces = []string{restrictToNamespace} - break - } +func (c *Cluster) allWorkloads(namespace string) (map[resource.ID]workload, error) { + if namespace != "" { + if _, ok := c.getAllowedAndExistingNamespaces()[namespace]; !ok { + return map[resource.ID]workload{}, nil } } - var allworkloads []cluster.Workload - for _, ns := range namespaces { - for kind, resourceKind := range resourceKinds { - workloads, err := resourceKind.getWorkloads(ctx, c, ns) - if err != nil { - switch { - case apierrors.IsNotFound(err): - // Kind not supported by API server, skip - continue - case apierrors.IsForbidden(err): - // K8s can return forbidden instead of not found for non super admins - c.logger.Log("warning", "not allowed to list resources", "err", err) - continue - default: - return nil, err - } - } + c.workloadsLock.RLock() + defer c.workloadsLock.RUnlock() - for _, workload := range workloads { - if !isAddon(workload) { - id := resource.MakeID(workload.GetNamespace(), kind, workload.GetName()) - c.muSyncErrors.RLock() - workload.syncError = c.syncErrors[id] - c.muSyncErrors.RUnlock() - allworkloads = append(allworkloads, workload.toClusterWorkload(id)) - } - } + allworkloads := map[resource.ID]workload{} + for id, workload := range c.workloadsById { + if !isAddon(workload) && namespace == "" || workload.GetNamespace() == namespace { + allworkloads[id] = workload } } - return allworkloads, nil } -func (c *Cluster) setSyncErrors(errs cluster.SyncError) { - c.muSyncErrors.Lock() - defer c.muSyncErrors.Unlock() - c.syncErrors = make(map[resource.ID]error) - for _, e := range errs { - c.syncErrors[e.ResourceID] = e.Error +// AllWorkloads returns all workloads in allowed namespaces matching the criteria; that is, in +// the namespace (or any namespace if that argument is empty) +func (c *Cluster) AllWorkloads(ctx context.Context, namespace string) ([]cluster.Workload, error) { + workloads, err := c.allWorkloads(namespace) + if err != nil { + return nil, err } + + var allworkloads []cluster.Workload + for id, workload := range workloads { + c.muSyncErrors.RLock() + workload.syncError = c.syncErrors[id] + c.muSyncErrors.RUnlock() + allworkloads = append(allworkloads, workload.toClusterWorkload(id)) + } + + return allworkloads, nil } func (c *Cluster) Ping() error { @@ -242,51 +307,29 @@ func (c *Cluster) Ping() error { func (c *Cluster) Export(ctx context.Context) ([]byte, error) { var config bytes.Buffer - namespaces, err := c.getAllowedAndExistingNamespaces(ctx) - if err != nil { - return nil, errors.Wrap(err, "getting namespaces") - } + namespacesByName := c.getAllowedAndExistingNamespaces() encoder := yaml.NewEncoder(&config) defer encoder.Close() - for _, ns := range namespaces { - namespace, err := c.client.CoreV1().Namespaces().Get(ns, meta_v1.GetOptions{}) - if err != nil { - return nil, err - } + for _, namespace := range namespacesByName { // kind & apiVersion must be set, since TypeMeta is not populated namespace.Kind = "Namespace" namespace.APIVersion = "v1" - err = encoder.Encode(yamlThroughJSON{namespace}) + err := encoder.Encode(yamlThroughJSON{namespace}) if err != nil { return nil, errors.Wrap(err, "marshalling namespace to YAML") } + workloads, err := c.allWorkloads(namespace.Name) + if err != nil { + return nil, err + } - for _, resourceKind := range resourceKinds { - workloads, err := resourceKind.getWorkloads(ctx, c, ns) - if err != nil { - switch { - case apierrors.IsNotFound(err): - // Kind not supported by API server, skip - continue - case apierrors.IsForbidden(err): - // K8s can return forbidden instead of not found for non super admins - c.logger.Log("warning", "not allowed to list resources", "err", err) - continue - default: - return nil, err - } - } - - for _, pc := range workloads { - if !isAddon(pc) { - if err := encoder.Encode(yamlThroughJSON{pc.k8sObject}); err != nil { - return nil, err - } - } + for _, pc := range workloads { + if err := encoder.Encode(yamlThroughJSON{pc.k8sObject}); err != nil { + return nil, err } } } @@ -307,35 +350,14 @@ func (c *Cluster) PublicSSHKey(regenerate bool) (ssh.PublicKey, error) { // the Flux instance is expected to have access to and can look for resources inside of. // It returns a list of all namespaces unless an explicit list of allowed namespaces // has been set on the Cluster instance. -func (c *Cluster) getAllowedAndExistingNamespaces(ctx context.Context) ([]string, error) { - if len(c.allowedNamespaces) > 0 { - nsList := []string{} - for name, _ := range c.allowedNamespaces { - if err := ctx.Err(); err != nil { - return nil, err - } - ns, err := c.client.CoreV1().Namespaces().Get(name, meta_v1.GetOptions{}) - switch { - case err == nil: - c.loggedAllowedNS[name] = false // reset, so if the namespace goes away we'll log it again - nsList = append(nsList, ns.Name) - case apierrors.IsUnauthorized(err) || apierrors.IsForbidden(err) || apierrors.IsNotFound(err): - if !c.loggedAllowedNS[name] { - c.logger.Log("warning", "cannot access allowed namespace", - "namespace", name, "err", err) - c.loggedAllowedNS[name] = true - } - default: - return nil, err - } - } - return nsList, nil - } - - if err := ctx.Err(); err != nil { - return nil, err +func (c *Cluster) getAllowedAndExistingNamespaces() map[string]v1.Namespace { + result := map[string]v1.Namespace{} + c.allowedAndExistingNamespacesLock.RLock() + defer c.allowedAndExistingNamespacesLock.RUnlock() + for name, ns := range c.allowedAndExistingNamespacesByName { + result[name] = ns } - return []string{meta_v1.NamespaceAll}, nil + return result } func (c *Cluster) IsAllowedResource(id resource.ID) bool { diff --git a/pkg/cluster/kubernetes/kubernetes_test.go b/pkg/cluster/kubernetes/kubernetes_test.go deleted file mode 100644 index 9c18229a0..000000000 --- a/pkg/cluster/kubernetes/kubernetes_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package kubernetes - -import ( - "context" - "reflect" - "sort" - "testing" - - "github.com/go-kit/kit/log" - apiv1 "k8s.io/api/core/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - fakekubernetes "k8s.io/client-go/kubernetes/fake" -) - -func newNamespace(name string) *apiv1.Namespace { - return &apiv1.Namespace{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: name, - }, - TypeMeta: meta_v1.TypeMeta{ - APIVersion: "v1", - Kind: "Namespace", - }, - } -} - -func testGetAllowedNamespaces(t *testing.T, namespace []string, expected []string) { - clientset := fakekubernetes.NewSimpleClientset(newNamespace("default"), - newNamespace("kube-system")) - client := ExtendedClient{coreClient: clientset} - allowedNamespaces := make(map[string]struct{}) - for _, n := range namespace { - allowedNamespaces[n] = struct{}{} - } - c := NewCluster(client, nil, nil, log.NewNopLogger(), allowedNamespaces, nil, []string{}) - - namespaces, err := c.getAllowedAndExistingNamespaces(context.Background()) - if err != nil { - t.Errorf("The error should be nil, not: %s", err) - } - - sort.Strings(namespaces) // We cannot be sure of the namespace order, since they are saved in a map in cluster struct - sort.Strings(expected) - - if reflect.DeepEqual(namespaces, expected) != true { - t.Errorf("Unexpected namespaces: %v != %v.", namespaces, expected) - } -} - -func TestGetAllowedNamespacesDefault(t *testing.T) { - testGetAllowedNamespaces(t, []string{}, []string{""}) // this will be empty string which means all namespaces -} - -func TestGetAllowedNamespacesNamespacesIsNil(t *testing.T) { - testGetAllowedNamespaces(t, nil, []string{""}) // this will be empty string which means all namespaces -} - -func TestGetAllowedNamespacesNamespacesSet(t *testing.T) { - testGetAllowedNamespaces(t, []string{"default"}, []string{"default"}) -} - -func TestGetAllowedNamespacesNamespacesSetDoesNotExist(t *testing.T) { - testGetAllowedNamespaces(t, []string{"hello"}, []string{}) -} - -func TestGetAllowedNamespacesNamespacesMultiple(t *testing.T) { - testGetAllowedNamespaces(t, []string{"default", "hello", "kube-system"}, []string{"default", "kube-system"}) -} diff --git a/pkg/cluster/kubernetes/manifests_test.go b/pkg/cluster/kubernetes/manifests_test.go index ceb4e5725..2548c3f53 100644 --- a/pkg/cluster/kubernetes/manifests_test.go +++ b/pkg/cluster/kubernetes/manifests_test.go @@ -9,15 +9,13 @@ import ( "github.com/go-kit/kit/log" "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" "github.com/fluxcd/flux/pkg/cluster/kubernetes/testfiles" ) func TestLocalCRDScope(t *testing.T) { - coreClient := makeFakeClient() - - nser, err := NewNamespacer(coreClient.Discovery(), "") + nser, err := newNamespacer("", &mockResourceInfoProvider{}) assert.NoError(t, err) manifests := NewManifests(nser, log.NewLogfmtLogger(os.Stdout)) @@ -62,9 +60,12 @@ metadata: } func TestUnKnownCRDScope(t *testing.T) { - coreClient := makeFakeClient() - - nser, err := NewNamespacer(coreClient.Discovery(), "") + infoProvider := &mockResourceInfoProvider{ + isNamespaced: map[schema.GroupKind]bool{ + {"", "Namespace"}: false, + }, + } + nser, err := newNamespacer("", infoProvider) assert.NoError(t, err) logBuffer := bytes.NewBuffer(nil) manifests := NewManifests(nser, log.NewLogfmtLogger(logBuffer)) @@ -106,14 +107,7 @@ metadata: assert.Equal(t, logBuffer.String(), savedLog) // But getting the scope of the CRD should result in a log saying we found the scope - apiResourcesWithoutFoo := coreClient.Resources - apiResource := &metav1.APIResourceList{ - GroupVersion: "foo.example.com/v1beta1", - APIResources: []metav1.APIResource{ - {Name: "foos", SingularName: "foo", Namespaced: true, Kind: "Foo"}, - }, - } - coreClient.Resources = append(coreClient.Resources, apiResource) + infoProvider.isNamespaced[schema.GroupKind{"foo.example.com", "Foo"}] = true logBuffer.Reset() resources, err = manifests.LoadManifests(dir, []string{dir}) @@ -122,7 +116,7 @@ metadata: assert.Contains(t, logBuffer.String(), "found scope of resource bar:foo/fooinstance") // and missing the scope information again should result in another warning - coreClient.Resources = apiResourcesWithoutFoo + delete(infoProvider.isNamespaced, schema.GroupKind{"foo.example.com", "Foo"}) logBuffer.Reset() resources, err = manifests.LoadManifests(dir, []string{dir}) assert.NoError(t, err) diff --git a/pkg/cluster/kubernetes/namespacer.go b/pkg/cluster/kubernetes/namespacer.go index f238c2992..77b41735a 100644 --- a/pkg/cluster/kubernetes/namespacer.go +++ b/pkg/cluster/kubernetes/namespacer.go @@ -1,11 +1,9 @@ package kubernetes import ( - "fmt" - + "github.com/argoproj/argo-cd/engine/pkg/utils/kube" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/discovery" "k8s.io/client-go/tools/clientcmd" kresource "github.com/fluxcd/flux/pkg/cluster/kubernetes/resource" @@ -17,28 +15,27 @@ import ( // namespace. const defaultFallbackNamespace = "default" -type namespaceViaDiscovery struct { +type namespacerViaInfoProvider struct { fallbackNamespace string - disco discovery.DiscoveryInterface + infoProvider kube.ResourceInfoProvider } -// NewNamespacer creates an implementation of Namespacer // If not empty `defaultNamespaceOverride` is used as the namespace when // a resource doesn't have a namespace specified. If empty the namespace // from the context in the KUBECONFIG is used, otherwise the "default" // namespace is used mimicking kubectl behavior -func NewNamespacer(d discovery.DiscoveryInterface, defaultNamespaceOverride string) (*namespaceViaDiscovery, error) { +func getFallbackNamespace(defaultNamespaceOverride string) (string, error) { if defaultNamespaceOverride != "" { - return &namespaceViaDiscovery{fallbackNamespace: defaultNamespaceOverride, disco: d}, nil + return defaultNamespaceOverride, nil } kubeconfigDefaultNamespace, err := getKubeconfigDefaultNamespace() if err != nil { - return nil, err + return "", err } if kubeconfigDefaultNamespace != "" { - return &namespaceViaDiscovery{fallbackNamespace: kubeconfigDefaultNamespace, disco: d}, nil + return kubeconfigDefaultNamespace, nil } - return &namespaceViaDiscovery{fallbackNamespace: defaultFallbackNamespace, disco: d}, nil + return defaultFallbackNamespace, nil } // getKubeconfigDefaultNamespace returns the namespace specified @@ -64,7 +61,7 @@ var getKubeconfigDefaultNamespace = func() (string, error) { // effectiveNamespace yields the namespace that would be used for this // resource were it applied, taking into account the kind of the // resource, and local configuration. -func (n *namespaceViaDiscovery) EffectiveNamespace(m kresource.KubeManifest, knownScopes ResourceScopes) (string, error) { +func (n *namespacerViaInfoProvider) EffectiveNamespace(m kresource.KubeManifest, knownScopes ResourceScopes) (string, error) { namespaced, err := n.lookupNamespaced(m.GroupVersion(), m.GetKind(), knownScopes) switch { case err != nil: @@ -77,8 +74,10 @@ func (n *namespaceViaDiscovery) EffectiveNamespace(m kresource.KubeManifest, kno return m.GetNamespace(), nil } -func (n *namespaceViaDiscovery) lookupNamespaced(groupVersion string, kind string, knownScopes ResourceScopes) (bool, error) { +func (n *namespacerViaInfoProvider) lookupNamespaced(groupVersion string, kind string, knownScopes ResourceScopes) (bool, error) { namespaced, clusterErr := n.lookupNamespacedInCluster(groupVersion, kind) + // FIXME: this doesn't work as it should since lookupNamespacedInCluster() doesn't return + // an error if the resource doesn't exist if clusterErr == nil || knownScopes == nil { return namespaced, nil } @@ -94,16 +93,14 @@ func (n *namespaceViaDiscovery) lookupNamespaced(groupVersion string, kind strin return scope == v1beta1.NamespaceScoped, nil } -func (n *namespaceViaDiscovery) lookupNamespacedInCluster(groupVersion, kind string) (bool, error) { - resourceList, err := n.disco.ServerResourcesForGroupVersion(groupVersion) +func (n *namespacerViaInfoProvider) lookupNamespacedInCluster(groupVersion, kind string) (bool, error) { + gv, err := schema.ParseGroupVersion(groupVersion) if err != nil { - return false, fmt.Errorf("error looking up API resources for %s.%s: %s", kind, groupVersion, err.Error()) + return false, err } - for _, resource := range resourceList.APIResources { - if resource.Kind == kind { - return resource.Namespaced, nil - } + vk := schema.GroupKind{ + Group: gv.Group, + Kind: kind, } - - return false, fmt.Errorf("resource not found for API %s, kind %s", groupVersion, kind) + return n.infoProvider.IsNamespaced(vk) } diff --git a/pkg/cluster/kubernetes/namespacer_test.go b/pkg/cluster/kubernetes/namespacer_test.go index c853ce4af..1b9706eb2 100644 --- a/pkg/cluster/kubernetes/namespacer_test.go +++ b/pkg/cluster/kubernetes/namespacer_test.go @@ -1,43 +1,34 @@ package kubernetes import ( + "errors" "io/ioutil" "os" "testing" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - corefake "k8s.io/client-go/kubernetes/fake" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube" + "k8s.io/apimachinery/pkg/runtime/schema" kresource "github.com/fluxcd/flux/pkg/cluster/kubernetes/resource" ) -var getAndList = metav1.Verbs([]string{"get", "list"}) - -func makeFakeClient() *corefake.Clientset { - apiResources := []*metav1.APIResourceList{ - { - GroupVersion: "apps/v1", - APIResources: []metav1.APIResource{ - {Name: "deployments", SingularName: "deployment", Namespaced: true, Kind: "Deployment", Verbs: getAndList}, - }, - }, - { - GroupVersion: "v1", - APIResources: []metav1.APIResource{ - {Name: "namespaces", SingularName: "namespace", Namespaced: false, Kind: "Namespace", Verbs: getAndList}, - }, - }, - { - GroupVersion: "apiextensions.k8s.io/v1beta1", - APIResources: []metav1.APIResource{ - {Name: "customresourcedefinitions", SingularName: "customresourcedefinition", Namespaced: false, Kind: "CustomResourceDefinition", Verbs: getAndList}, - }, - }, +type mockResourceInfoProvider struct { + isNamespaced map[schema.GroupKind]bool +} + +func (m *mockResourceInfoProvider) IsNamespaced(gk schema.GroupKind) (bool, error) { + if namespaced, ok := m.isNamespaced[gk]; ok { + return namespaced, nil } + return false, errors.New("not found") +} - coreClient := corefake.NewSimpleClientset() - coreClient.Fake.Resources = apiResources - return coreClient +func newNamespacer(defaultNamespace string, scoper kube.ResourceInfoProvider) (*namespacerViaInfoProvider, error) { + fallbackNamespace, err := getFallbackNamespace(defaultNamespace) + if err != nil { + return nil, err + } + return &namespacerViaInfoProvider{infoProvider: scoper, fallbackNamespace: fallbackNamespace}, nil } func TestNamespaceDefaulting(t *testing.T) { @@ -62,7 +53,6 @@ users: [] os.Setenv("KUBECONFIG", "testkubeconfig") defer os.Unsetenv("KUBECONFIG") - coreClient := makeFakeClient() ns, err := getKubeconfigDefaultNamespace() if err != nil { @@ -96,11 +86,12 @@ metadata: t.Fatal(err) } - defaultNser, err := NewNamespacer(coreClient.Discovery(), "") + scoper := &mockResourceInfoProvider{map[schema.GroupKind]bool{{"apps", "Deployment"}: true}} + defaultNser, err := newNamespacer("", scoper) if err != nil { t.Fatal(err) } - assertEffectiveNamespace := func(nser namespaceViaDiscovery, id, expected string) { + assertEffectiveNamespace := func(nser namespacerViaInfoProvider, id, expected string) { res, ok := manifests[id] if !ok { t.Errorf("manifest for %q not found", id) @@ -120,7 +111,7 @@ metadata: assertEffectiveNamespace(*defaultNser, ":deployment/noNamespace", "namespace") assertEffectiveNamespace(*defaultNser, "spurious:namespace/notNamespaced", "") - overrideNser, err := NewNamespacer(coreClient.Discovery(), "foo-override") + overrideNser, err := newNamespacer("foo-override", scoper) if err != nil { t.Fatal(err) } diff --git a/pkg/cluster/kubernetes/resourcekinds.go b/pkg/cluster/kubernetes/resourcekinds.go index 0509afcc0..79757b19c 100644 --- a/pkg/cluster/kubernetes/resourcekinds.go +++ b/pkg/cluster/kubernetes/resourcekinds.go @@ -1,14 +1,13 @@ package kubernetes import ( - "context" + "encoding/json" "strings" - hr_v1 "github.com/fluxcd/helm-operator/pkg/apis/helm.fluxcd.io/v1" apiapps "k8s.io/api/apps/v1" apibatch "k8s.io/api/batch/v1beta1" apiv1 "k8s.io/api/core/v1" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" hr_v1beta1 "github.com/fluxcd/flux/integrations/apis/flux.weave.works/v1beta1" fhr_v1alpha2 "github.com/fluxcd/flux/integrations/apis/helm.integrations.flux.weave.works/v1alpha2" @@ -17,6 +16,7 @@ import ( "github.com/fluxcd/flux/pkg/image" "github.com/fluxcd/flux/pkg/policy" "github.com/fluxcd/flux/pkg/resource" + hr_v1 "github.com/fluxcd/helm-operator/pkg/apis/helm.fluxcd.io/v1" ) // AntecedentAnnotation is an annotation on a resource indicating that @@ -31,8 +31,7 @@ const AntecedentAnnotation = "flux.weave.works/antecedent" // Kind registry type resourceKind interface { - getWorkload(ctx context.Context, c *Cluster, namespace, name string) (workload, error) - getWorkloads(ctx context.Context, c *Cluster, namespace string) ([]workload, error) + getWorkload(obj *unstructured.Unstructured) (workload, error) } var ( @@ -115,35 +114,19 @@ func (w workload) toClusterWorkload(resourceID resource.ID) cluster.Workload { type deploymentKind struct{} -func (dk *deploymentKind) getWorkload(ctx context.Context, c *Cluster, namespace, name string) (workload, error) { - if err := ctx.Err(); err != nil { +func (dk *deploymentKind) getWorkload(obj *unstructured.Unstructured) (workload, error) { + data, err := json.Marshal(obj) + if err != nil { return workload{}, err } - deployment, err := c.client.AppsV1().Deployments(namespace).Get(name, meta_v1.GetOptions{}) + deployment := &apiapps.Deployment{} + err = json.Unmarshal(data, deployment) if err != nil { return workload{}, err } - return makeDeploymentWorkload(deployment), nil } -func (dk *deploymentKind) getWorkloads(ctx context.Context, c *Cluster, namespace string) ([]workload, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - deployments, err := c.client.AppsV1().Deployments(namespace).List(meta_v1.ListOptions{}) - if err != nil { - return nil, err - } - - var workloads []workload - for i := range deployments.Items { - workloads = append(workloads, makeDeploymentWorkload(&deployments.Items[i])) - } - - return workloads, nil -} - // Deployment may get stuck trying to deploy its newest ReplicaSet without ever completing. // One way to detect this condition is to specify a deadline parameter in Deployment spec: // .spec.progressDeadlineSeconds @@ -198,35 +181,19 @@ func makeDeploymentWorkload(deployment *apiapps.Deployment) workload { type daemonSetKind struct{} -func (dk *daemonSetKind) getWorkload(ctx context.Context, c *Cluster, namespace, name string) (workload, error) { - if err := ctx.Err(); err != nil { +func (dk *daemonSetKind) getWorkload(obj *unstructured.Unstructured) (workload, error) { + data, err := json.Marshal(obj) + if err != nil { return workload{}, err } - daemonSet, err := c.client.AppsV1().DaemonSets(namespace).Get(name, meta_v1.GetOptions{}) + daemonSet := &apiapps.DaemonSet{} + err = json.Unmarshal(data, daemonSet) if err != nil { return workload{}, err } - return makeDaemonSetWorkload(daemonSet), nil } -func (dk *daemonSetKind) getWorkloads(ctx context.Context, c *Cluster, namespace string) ([]workload, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - daemonSets, err := c.client.AppsV1().DaemonSets(namespace).List(meta_v1.ListOptions{}) - if err != nil { - return nil, err - } - - var workloads []workload - for i := range daemonSets.Items { - workloads = append(workloads, makeDaemonSetWorkload(&daemonSets.Items[i])) - } - - return workloads, nil -} - func makeDaemonSetWorkload(daemonSet *apiapps.DaemonSet) workload { var status string objectMeta, daemonSetStatus := daemonSet.ObjectMeta, daemonSet.Status @@ -265,35 +232,19 @@ func makeDaemonSetWorkload(daemonSet *apiapps.DaemonSet) workload { type statefulSetKind struct{} -func (dk *statefulSetKind) getWorkload(ctx context.Context, c *Cluster, namespace, name string) (workload, error) { - if err := ctx.Err(); err != nil { +func (dk *statefulSetKind) getWorkload(obj *unstructured.Unstructured) (workload, error) { + data, err := json.Marshal(obj) + if err != nil { return workload{}, err } - statefulSet, err := c.client.AppsV1().StatefulSets(namespace).Get(name, meta_v1.GetOptions{}) + statefulSet := &apiapps.StatefulSet{} + err = json.Unmarshal(data, statefulSet) if err != nil { return workload{}, err } - return makeStatefulSetWorkload(statefulSet), nil } -func (dk *statefulSetKind) getWorkloads(ctx context.Context, c *Cluster, namespace string) ([]workload, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - statefulSets, err := c.client.AppsV1().StatefulSets(namespace).List(meta_v1.ListOptions{}) - if err != nil { - return nil, err - } - - var workloads []workload - for i := range statefulSets.Items { - workloads = append(workloads, makeStatefulSetWorkload(&statefulSets.Items[i])) - } - - return workloads, nil -} - func makeStatefulSetWorkload(statefulSet *apiapps.StatefulSet) workload { var status string objectMeta, statefulSetStatus := statefulSet.ObjectMeta, statefulSet.Status @@ -364,35 +315,19 @@ func makeStatefulSetWorkload(statefulSet *apiapps.StatefulSet) workload { type cronJobKind struct{} -func (dk *cronJobKind) getWorkload(ctx context.Context, c *Cluster, namespace, name string) (workload, error) { - if err := ctx.Err(); err != nil { +func (dk *cronJobKind) getWorkload(obj *unstructured.Unstructured) (workload, error) { + data, err := json.Marshal(obj) + if err != nil { return workload{}, err } - cronJob, err := c.client.BatchV1beta1().CronJobs(namespace).Get(name, meta_v1.GetOptions{}) + cronJob := &apibatch.CronJob{} + err = json.Unmarshal(data, cronJob) if err != nil { return workload{}, err } - return makeCronJobWorkload(cronJob), nil } -func (dk *cronJobKind) getWorkloads(ctx context.Context, c *Cluster, namespace string) ([]workload, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - cronJobs, err := c.client.BatchV1beta1().CronJobs(namespace).List(meta_v1.ListOptions{}) - if err != nil { - return nil, err - } - - var workloads []workload - for i, _ := range cronJobs.Items { - workloads = append(workloads, makeCronJobWorkload(&cronJobs.Items[i])) - } - - return workloads, nil -} - func makeCronJobWorkload(cronJob *apibatch.CronJob) workload { cronJob.APIVersion = "batch/v1beta1" cronJob.Kind = "CronJob" @@ -407,34 +342,19 @@ func makeCronJobWorkload(cronJob *apibatch.CronJob) workload { type fluxHelmReleaseKind struct{} -func (fhr *fluxHelmReleaseKind) getWorkload(ctx context.Context, c *Cluster, namespace, name string) (workload, error) { - if err := ctx.Err(); err != nil { +func (fhr *fluxHelmReleaseKind) getWorkload(obj *unstructured.Unstructured) (workload, error) { + data, err := json.Marshal(obj) + if err != nil { return workload{}, err } - fluxHelmRelease, err := c.client.HelmV1alpha2().FluxHelmReleases(namespace).Get(name, meta_v1.GetOptions{}) + fluxHelmRelease := &fhr_v1alpha2.FluxHelmRelease{} + err = json.Unmarshal(data, fluxHelmRelease) if err != nil { return workload{}, err } return makeFluxHelmReleaseWorkload(fluxHelmRelease), nil } -func (fhr *fluxHelmReleaseKind) getWorkloads(ctx context.Context, c *Cluster, namespace string) ([]workload, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - fluxHelmReleases, err := c.client.HelmV1alpha2().FluxHelmReleases(namespace).List(meta_v1.ListOptions{}) - if err != nil { - return nil, err - } - - var workloads []workload - for i, _ := range fluxHelmReleases.Items { - workloads = append(workloads, makeFluxHelmReleaseWorkload(&fluxHelmReleases.Items[i])) - } - - return workloads, nil -} - func makeFluxHelmReleaseWorkload(fluxHelmRelease *fhr_v1alpha2.FluxHelmRelease) workload { containers := createK8sHRContainers(fluxHelmRelease.ObjectMeta.Annotations, fluxHelmRelease.Spec.Values) @@ -484,50 +404,23 @@ type helmReleaseKind struct{} // case v1beta1 is not active in the cluster at all. One potential // solution may be to collect both errors and see if one outweighs // the other. -func (hr *helmReleaseKind) getWorkload(ctx context.Context, c *Cluster, namespace, name string) (workload, error) { - if err := ctx.Err(); err != nil { - return workload{}, err - } - if helmRelease, err := c.client.HelmV1().HelmReleases(namespace).Get(name, meta_v1.GetOptions{}); err == nil { - return makeHelmReleaseStableWorkload(helmRelease), err - } - helmRelease, err := c.client.FluxV1beta1().HelmReleases(namespace).Get(name, meta_v1.GetOptions{}) +func (hr *helmReleaseKind) getWorkload(obj *unstructured.Unstructured) (workload, error) { + data, err := json.Marshal(obj) if err != nil { return workload{}, err } - return makeHelmReleaseBetaWorkload(helmRelease), nil -} - -// getWorkloads collects v1 and v1beta1 HelmRelease workloads, if the -// same workload (by name) is found for two versions, only the v1 -// version is returned. This is so that the workload results returned -// by this method are always valid for `getWorkload` and return the -// same resource. -// TODO(hidde): again, the cost of backwards compatibility is silencing -// errors. -func (hr *helmReleaseKind) getWorkloads(ctx context.Context, c *Cluster, namespace string) ([]workload, error) { - if err := ctx.Err(); err != nil { - return nil, err - } - names := make(map[string]bool, 0) - workloads := make([]workload, 0) - if helmReleases, err := c.client.HelmV1().HelmReleases(namespace).List(meta_v1.ListOptions{}); err == nil { - for i, _ := range helmReleases.Items { - workload := makeHelmReleaseStableWorkload(&helmReleases.Items[i]) - workloads = append(workloads, workload) - names[workload.GetName()] = true - } - } - if helmReleases, err := c.client.FluxV1beta1().HelmReleases(namespace).List(meta_v1.ListOptions{}); err == nil { - for i, _ := range helmReleases.Items { - workload := makeHelmReleaseBetaWorkload(&helmReleases.Items[i]) - if names[workload.GetName()] { - continue - } - workloads = append(workloads, workload) + helmRelease := &hr_v1.HelmRelease{} + err = json.Unmarshal(data, helmRelease) + if err == nil { + return makeHelmReleaseStableWorkload(helmRelease), err + } else { + helmRelease := &hr_v1beta1.HelmRelease{} + err = json.Unmarshal(data, helmRelease) + if err != nil { + return workload{}, err } + return makeHelmReleaseBetaWorkload(helmRelease), nil } - return workloads, nil } func makeHelmReleaseBetaWorkload(helmRelease *hr_v1beta1.HelmRelease) workload { diff --git a/pkg/cluster/kubernetes/sync.go b/pkg/cluster/kubernetes/sync.go index 5883e2289..12461e3a5 100644 --- a/pkg/cluster/kubernetes/sync.go +++ b/pkg/cluster/kubernetes/sync.go @@ -1,29 +1,19 @@ package kubernetes import ( - "bytes" "context" - "crypto/sha1" "crypto/sha256" "encoding/base64" - "encoding/hex" + "encoding/json" "fmt" - "github.com/ryanuber/go-glob" - "io" - "os/exec" - "sort" - "strings" - "time" - "github.com/go-kit/kit/log" - "github.com/imdario/mergo" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube/cache" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube/sync" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube/sync/common" + yamlutil "github.com/ghodss/yaml" "github.com/pkg/errors" - "gopkg.in/yaml.v2" - apierrors "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/rest" "github.com/fluxcd/flux/pkg/cluster" kresource "github.com/fluxcd/flux/pkg/cluster/kubernetes/resource" @@ -41,124 +31,90 @@ const ( checksumAnnotation = kresource.PolicyPrefix + "sync-checksum" ) +func unmarshalResources(resourcesByID []resource.Resource) ([]*unstructured.Unstructured, error) { + var resources []*unstructured.Unstructured + for _, res := range resourcesByID { + data, err := yamlutil.YAMLToJSON(res.Bytes()) + if err != nil { + return nil, err + } + un := &unstructured.Unstructured{} + err = json.Unmarshal(data, un) + if err != nil { + return nil, err + } + resources = append(resources, un) + } + return resources, nil +} + +func isManagedResource(r *cache.Resource) bool { + return r.Resource != nil +} + // Sync takes a definition of what should be running in the cluster, // and attempts to make the cluster conform. An error return does not // necessarily indicate complete failure; some resources may succeed // in being synced, and some may fail (for example, they may be // malformed). func (c *Cluster) Sync(syncSet cluster.SyncSet) error { - logger := log.With(c.logger, "method", "Sync") - - // Keep track of the checksum of each resource, so we can compare - // them during garbage collection. - checksums := map[string]string{} - - // NB we get all resources, since we care about leaving unsynced, - // _ignored_ resources alone. - clusterResources, err := c.getAllowedResourcesBySelector("") - if err != nil { - return errors.Wrap(err, "collating resources in cluster for sync") - } - - cs := makeChangeSet() - var errs cluster.SyncError - var excluded []string + sourceById := map[string]string{} for _, res := range syncSet.Resources { - resID := res.ResourceID() - id := resID.String() - if !c.IsAllowedResource(resID) { - excluded = append(excluded, id) - continue - } - // make a record of the checksum, whether we stage it to - // be applied or not, so that we don't delete it later. - csum := sha1.Sum(res.Bytes()) - checkHex := hex.EncodeToString(csum[:]) - checksums[id] = checkHex - if res.Policies().Has(policy.Ignore) { - logger.Log("info", "not applying resource; ignore annotation in file", "resource", res.ResourceID(), "source", res.Source()) - continue - } - // It's possible to give a cluster resource the "ignore" - // annotation directly -- e.g., with `kubectl annotate` -- so - // we need to examine the cluster resource here too. - if cres, ok := clusterResources[id]; ok && cres.Policies().Has(policy.Ignore) { - logger.Log("info", "not applying resource; ignore annotation in cluster resource", "resource", cres.ResourceID()) - continue - } - resBytes, err := applyMetadata(res, syncSet.Name, checkHex) - if err == nil { - cs.stage("apply", res.ResourceID(), res.Source(), resBytes) - } else { - errs = append(errs, cluster.ResourceError{ResourceID: res.ResourceID(), Source: res.Source(), Error: err}) - break - } + sourceById[res.ResourceID().String()] = res.Source() } - - if len(excluded) > 0 { - logger.Log("warning", "not applying resources; excluded by namespace constraints", "resources", strings.Join(excluded, ",")) - } - - c.mu.Lock() - defer c.mu.Unlock() - c.muSyncErrors.RLock() - if applyErrs := c.applier.apply(logger, cs, c.syncErrors); len(applyErrs) > 0 { - errs = append(errs, applyErrs...) - } - c.muSyncErrors.RUnlock() - - if c.GC || c.DryGC { - deleteErrs, gcFailure := c.collectGarbage(syncSet, checksums, logger, c.DryGC) - if gcFailure != nil { - return gcFailure - } - errs = append(errs, deleteErrs...) - } - - // If `nil`, errs is a cluster.SyncError(nil) rather than error(nil), so it cannot be returned directly. - if errs == nil { - return nil + resources, err := unmarshalResources(syncSet.Resources) + if err != nil { + return errors.Wrap(err, "unmarshalling repository resources") } - // It is expected that Cluster.Sync is invoked with *all* resources. - // Otherwise it will override previously recorded sync errors. - c.setSyncErrors(errs) - return errs -} - -func (c *Cluster) collectGarbage( - syncSet cluster.SyncSet, - checksums map[string]string, - logger log.Logger, - dryRun bool) (cluster.SyncError, error) { - - orphanedResources := makeChangeSet() - - clusterResources, err := c.getAllowedGCMarkedResourcesInSyncSet(syncSet.Name) + result, err := c.engine.Sync(context.Background(), resources, isManagedResource, syncSet.Name, c.fallbackNamespace, sync.WithResourcesFilter( + func(key kube.ResourceKey, live *unstructured.Unstructured, target *unstructured.Unstructured) bool { + if live != nil { + // don't GC resources that were not deployed by Flux with the same configuration + if target == nil && !allowedForGC(live, syncSet.Name) { + return false + } + if kresource.PoliciesFromAnnotations(live.GetAnnotations()).Has(policy.Ignore) { + return false + } + } + if target != nil { + if kresource.PoliciesFromAnnotations(target.GetAnnotations()).Has(policy.Ignore) { + return false + } + labels := target.GetLabels() + if labels == nil { + labels = map[string]string{} + } + labels[gcMarkLabel] = makeGCMark(syncSet.Name, resource.MakeID(target.GetNamespace(), target.GetKind(), target.GetName()).String()) + target.SetLabels(labels) + } + return true + }), sync.WithOperationSettings(false, c.GC && !c.DryGC, false, false), + ) if err != nil { - return nil, errors.Wrap(err, "collating resources in cluster for calculating garbage collection") + return err } - for resourceID, res := range clusterResources { - actual := res.GetChecksum() - expected, ok := checksums[resourceID] - - switch { - case !ok: // was not recorded as having been staged for application - c.logger.Log("info", "cluster resource not in resources to be synced; deleting", "dry-run", dryRun, "resource", resourceID) - if !dryRun { - orphanedResources.stage("delete", res.ResourceID(), "", res.IdentifyingBytes()) + var resourceErrors []cluster.ResourceError + for _, res := range result { + if res.Status == common.ResultCodeSyncFailed { + id := resource.MakeID(res.ResourceKey.Namespace, res.ResourceKey.Kind, res.ResourceKey.Name) + source := "" + if src, ok := sourceById[id.String()]; ok { + source = src } - case actual != expected: - c.logger.Log("warning", "resource to be synced has not been updated; skipping", "dry-run", dryRun, "resource", resourceID) - continue - default: - // The checksum is the same, indicating that it was - // applied earlier. Leave it alone. + resourceErrors = append(resourceErrors, cluster.ResourceError{ + ResourceID: id, + Source: source, + Error: errors.New(res.Message), + }) } } - - return c.applier.apply(logger, orphanedResources, nil), nil + if len(resourceErrors) > 0 { + return cluster.SyncError(resourceErrors) + } + return nil } // --- internals in support of Sync @@ -202,205 +158,9 @@ func (r *kuberesource) GetGCMark() string { return r.obj.GetLabels()[gcMarkLabel] } -func (c *Cluster) filterResources(resources *meta_v1.APIResourceList) *meta_v1.APIResourceList { - list := []meta_v1.APIResource{} - for _, apiResource := range resources.APIResources { - fullName := fmt.Sprintf("%s/%s", resources.GroupVersion, apiResource.Kind) - excluded := false - for _, exp := range c.resourceExcludeList { - if glob.Glob(exp, fullName) { - excluded = true - break - } - } - if !excluded { - list = append(list, apiResource) - } - } - - return &meta_v1.APIResourceList{ - TypeMeta: resources.TypeMeta, - GroupVersion: resources.GroupVersion, - APIResources: list, - } -} - -func (c *Cluster) getAllowedResourcesBySelector(selector string) (map[string]*kuberesource, error) { - listOptions := meta_v1.ListOptions{} - if selector != "" { - listOptions.LabelSelector = selector - } - - sgs, err := c.client.discoveryClient.ServerGroups() - if sgs == nil { - return nil, err - } - - resources := []*meta_v1.APIResourceList{} - for i := range sgs.Groups { - gv := sgs.Groups[i].PreferredVersion.GroupVersion - - excluded := false - for _, exp := range c.resourceExcludeList { - if glob.Glob(exp, fmt.Sprintf("%s/", gv)) { - excluded = true - break - } - } - - if !excluded { - if r, err := c.client.discoveryClient.ServerResourcesForGroupVersion(gv); err == nil { - if r != nil { - resources = append(resources, c.filterResources(r)) - } - } else { - // ignore errors for resources with empty group version instead of failing to sync - if err.Error() != fmt.Sprintf("Got empty response for: %v", gv) { - return nil, err - } - } - } - } - - result := map[string]*kuberesource{} - - contains := func(a []string, x string) bool { - for _, n := range a { - if x == n { - return true - } - } - return false - } - - for _, resource := range resources { - for _, apiResource := range resource.APIResources { - verbs := apiResource.Verbs - if !contains(verbs, "list") { - continue - } - groupVersion, err := schema.ParseGroupVersion(resource.GroupVersion) - if err != nil { - return nil, err - } - gvr := groupVersion.WithResource(apiResource.Name) - list, err := c.listAllowedResources(apiResource.Namespaced, gvr, listOptions) - if err != nil { - if apierrors.IsForbidden(err) { - // we are not allowed to list this resource but - // shouldn't prevent us from listing the rest - continue - } - return nil, err - } - - for i, item := range list { - apiVersion := item.GetAPIVersion() - kind := item.GetKind() - - itemDesc := fmt.Sprintf("%s:%s", apiVersion, kind) - // https://github.com/kontena/k8s-client/blob/6e9a7ba1f03c255bd6f06e8724a1c7286b22e60f/lib/k8s/stack.rb#L17-L22 - if itemDesc == "v1:ComponentStatus" || itemDesc == "v1:Endpoints" { - continue - } - - // exclude anything that has an ownerReference - owners := item.GetOwnerReferences() - if owners != nil && len(owners) > 0 { - continue - } - - res := &kuberesource{obj: &list[i], namespaced: apiResource.Namespaced} - result[res.ResourceID().String()] = res - } - } - } - - return result, nil -} - -func (c *Cluster) listAllowedResources( - namespaced bool, gvr schema.GroupVersionResource, options meta_v1.ListOptions) ([]unstructured.Unstructured, error) { - if !namespaced { - // The resource is not namespaced, everything is allowed - resourceClient := c.client.dynamicClient.Resource(gvr) - data, err := resourceClient.List(options) - if err != nil { - return nil, err - } - return data.Items, nil - } - - // List resources only from the allowed namespaces - namespaces, err := c.getAllowedAndExistingNamespaces(context.Background()) - if err != nil { - return nil, err - } - var result []unstructured.Unstructured - for _, ns := range namespaces { - data, err := c.client.dynamicClient.Resource(gvr).Namespace(ns).List(options) - if err != nil { - return result, err - } - result = append(result, data.Items...) - } - return result, nil -} - -func (c *Cluster) getAllowedGCMarkedResourcesInSyncSet(syncSetName string) (map[string]*kuberesource, error) { - allGCMarkedResources, err := c.getAllowedResourcesBySelector(gcMarkLabel) // means "gcMarkLabel exists" - if err != nil { - return nil, err - } - allowedSyncSetGCMarkedResources := map[string]*kuberesource{} - for resID, kres := range allGCMarkedResources { - // Discard resources whose mark doesn't match their resource ID - if kres.GetGCMark() != makeGCMark(syncSetName, resID) { - continue - } - allowedSyncSetGCMarkedResources[resID] = kres - } - return allowedSyncSetGCMarkedResources, nil -} - -func applyMetadata(res resource.Resource, syncSetName, checksum string) ([]byte, error) { - definition := map[interface{}]interface{}{} - if err := yaml.Unmarshal(res.Bytes(), &definition); err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("failed to parse yaml from %s", res.Source())) - } - - mixin := map[string]interface{}{} - - if syncSetName != "" { - mixinLabels := map[string]string{} - mixinLabels[gcMarkLabel] = makeGCMark(syncSetName, res.ResourceID().String()) - mixin["labels"] = mixinLabels - } - - // After loading the manifest the namespace of the resource can change - // (e.g. a default namespace is applied) - // The `ResourceID` should give us the up-to-date value - // (see `KubeManifest.SetNamespace`) - namespace, _, _ := res.ResourceID().Components() - if namespace != kresource.ClusterScope { - mixin["namespace"] = namespace - } - - if checksum != "" { - mixinAnnotations := map[string]string{} - mixinAnnotations[checksumAnnotation] = checksum - mixin["annotations"] = mixinAnnotations - } - - mergo.Merge(&definition, map[interface{}]interface{}{ - "metadata": mixin, - }) - - bytes, err := yaml.Marshal(definition) - if err != nil { - return nil, errors.Wrap(err, "failed to serialize yaml after applying metadata") - } - return bytes, nil +func allowedForGC(obj *unstructured.Unstructured, syncSetName string) bool { + res := kuberesource{obj: obj, namespaced: obj.GetNamespace() != ""} + return res.GetGCMark() == makeGCMark(syncSetName, res.ResourceID().String()) } func makeGCMark(syncSetName, resourceID string) string { @@ -412,197 +172,3 @@ func makeGCMark(syncSetName, resourceID string) string { // The prefix is to make sure it's a valid (Kubernetes) label value. return "sha256." + base64.RawURLEncoding.EncodeToString(hasher.Sum(nil)) } - -// --- internal types for keeping track of syncing - -type applyObject struct { - ResourceID resource.ID - Source string - Payload []byte -} - -type changeSet struct { - objs map[string][]applyObject -} - -func makeChangeSet() changeSet { - return changeSet{objs: make(map[string][]applyObject)} -} - -func (c *changeSet) stage(cmd string, id resource.ID, source string, bytes []byte) { - c.objs[cmd] = append(c.objs[cmd], applyObject{id, source, bytes}) -} - -// Applier is something that will apply a changeset to the cluster. -type Applier interface { - apply(log.Logger, changeSet, map[resource.ID]error) cluster.SyncError -} - -type Kubectl struct { - exe string - config *rest.Config -} - -func NewKubectl(exe string, config *rest.Config) *Kubectl { - return &Kubectl{ - exe: exe, - config: config, - } -} - -func (c *Kubectl) connectArgs() []string { - var args []string - if c.config.Host != "" { - args = append(args, fmt.Sprintf("--server=%s", c.config.Host)) - } - if c.config.Username != "" { - args = append(args, fmt.Sprintf("--username=%s", c.config.Username)) - } - if c.config.Password != "" { - args = append(args, fmt.Sprintf("--password=%s", c.config.Password)) - } - if c.config.TLSClientConfig.CertFile != "" { - args = append(args, fmt.Sprintf("--client-certificate=%s", c.config.TLSClientConfig.CertFile)) - } - if c.config.TLSClientConfig.CAFile != "" { - args = append(args, fmt.Sprintf("--certificate-authority=%s", c.config.TLSClientConfig.CAFile)) - } - if c.config.TLSClientConfig.KeyFile != "" { - args = append(args, fmt.Sprintf("--client-key=%s", c.config.TLSClientConfig.KeyFile)) - } - if c.config.BearerToken != "" { - args = append(args, fmt.Sprintf("--token=%s", c.config.BearerToken)) - } - return args -} - -// rankOfKind returns an int denoting the position of the given kind -// in the partial ordering of Kubernetes resources, according to which -// kinds depend on which (derived by hand). -func rankOfKind(kind string) int { - switch strings.ToLower(kind) { - // Namespaces answer to NOONE - case "namespace": - return 0 - // These don't go in namespaces; or do, but don't depend on anything else - case "customresourcedefinition", "serviceaccount", "clusterrole", "role", "persistentvolume", "service": - return 1 - // These depend on something above, but not each other - case "resourcequota", "limitrange", "secret", "configmap", "rolebinding", "clusterrolebinding", "persistentvolumeclaim", "ingress": - return 2 - // Same deal, next layer - case "daemonset", "deployment", "replicationcontroller", "replicaset", "job", "cronjob", "statefulset": - return 3 - // Assumption: anything not mentioned isn't depended _upon_, so - // can come last. - default: - return 4 - } -} - -type applyOrder []applyObject - -func (objs applyOrder) Len() int { - return len(objs) -} - -func (objs applyOrder) Swap(i, j int) { - objs[i], objs[j] = objs[j], objs[i] -} - -func (objs applyOrder) Less(i, j int) bool { - _, ki, ni := objs[i].ResourceID.Components() - _, kj, nj := objs[j].ResourceID.Components() - ranki, rankj := rankOfKind(ki), rankOfKind(kj) - if ranki == rankj { - return ni < nj - } - return ranki < rankj -} - -func (c *Kubectl) apply(logger log.Logger, cs changeSet, errored map[resource.ID]error) (errs cluster.SyncError) { - f := func(objs []applyObject, cmd string, args ...string) { - if len(objs) == 0 { - return - } - logger.Log("cmd", cmd, "args", strings.Join(args, " "), "count", len(objs)) - args = append(args, cmd) - - var multi, single []applyObject - if len(errored) == 0 { - multi = objs - } else { - for _, obj := range objs { - if _, ok := errored[obj.ResourceID]; ok { - // Resources that errored before shall be applied separately - single = append(single, obj) - } else { - // everything else will be tried in a multidoc apply. - multi = append(multi, obj) - } - } - } - - if len(multi) > 0 { - if err := c.doCommand(logger, makeMultidoc(multi), args...); err != nil { - single = append(single, multi...) - } - } - for _, obj := range single { - r := bytes.NewReader(obj.Payload) - if err := c.doCommand(logger, r, args...); err != nil { - errs = append(errs, cluster.ResourceError{ - ResourceID: obj.ResourceID, - Source: obj.Source, - Error: err, - }) - } - } - } - - // When deleting objects, the only real concern is that we don't - // try to delete things that have already been deleted by - // Kubernetes' GC -- most notably, resources in a namespace which - // is also being deleted. GC does not have the dependency ranking, - // but we can use it as a shortcut to avoid the above problem at - // least. - objs := cs.objs["delete"] - sort.Sort(sort.Reverse(applyOrder(objs))) - f(objs, "delete") - - objs = cs.objs["apply"] - sort.Sort(applyOrder(objs)) - f(objs, "apply") - return errs -} - -func (c *Kubectl) doCommand(logger log.Logger, r io.Reader, args ...string) error { - args = append(args, "-f", "-") - cmd := c.kubectlCommand(args...) - cmd.Stdin = r - stderr := &bytes.Buffer{} - cmd.Stderr = stderr - stdout := &bytes.Buffer{} - cmd.Stdout = stdout - - begin := time.Now() - err := cmd.Run() - if err != nil { - err = errors.Wrap(errors.New(strings.TrimSpace(stderr.String())), "running kubectl") - } - - logger.Log("cmd", "kubectl "+strings.Join(args, " "), "took", time.Since(begin), "err", err, "output", strings.TrimSpace(stdout.String())) - return err -} - -func makeMultidoc(objs []applyObject) *bytes.Buffer { - buf := &bytes.Buffer{} - for _, obj := range objs { - appendYAMLToBuffer(obj.Payload, buf) - } - return buf -} - -func (c *Kubectl) kubectlCommand(args ...string) *exec.Cmd { - return exec.Command(c.exe, append(c.connectArgs(), args...)...) -} diff --git a/pkg/cluster/kubernetes/sync_test.go b/pkg/cluster/kubernetes/sync_test.go index e276cfe39..4f80234a8 100644 --- a/pkg/cluster/kubernetes/sync_test.go +++ b/pkg/cluster/kubernetes/sync_test.go @@ -1,34 +1,27 @@ package kubernetes import ( + "context" "fmt" + "io" "os" - "sort" - "strings" "testing" - "github.com/ghodss/yaml" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube/cache" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube/sync" + "github.com/argoproj/argo-cd/engine/pkg/utils/kube/sync/common" + "github.com/go-kit/kit/log" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" - crdfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/discovery" - "k8s.io/client-go/dynamic" - dynamicfake "k8s.io/client-go/dynamic/fake" - k8sclient "k8s.io/client-go/kubernetes" corefake "k8s.io/client-go/kubernetes/fake" k8s_testing "k8s.io/client-go/testing" fhrfake "github.com/fluxcd/flux/integrations/client/clientset/versioned/fake" "github.com/fluxcd/flux/pkg/cluster" - kresource "github.com/fluxcd/flux/pkg/cluster/kubernetes/resource" - "github.com/fluxcd/flux/pkg/resource" - "github.com/fluxcd/flux/pkg/sync" helmopfake "github.com/fluxcd/helm-operator/pkg/client/clientset/versioned/fake" ) @@ -36,9 +29,17 @@ const ( defaultTestNamespace = "unusual-default" ) -func fakeClients() (ExtendedClient, func()) { - scheme := runtime.NewScheme() +type fakeEngine struct { +} + +func (e *fakeEngine) Run() (io.Closer, error) { + return nil, nil +} +func (e *fakeEngine) Sync(ctx context.Context, resources []*unstructured.Unstructured, isManaged func(r *cache.Resource) bool, revision string, namespace string, opts ...sync.SyncOpt) ([]common.ResourceSyncResult, error) { + return nil, nil +} +func fakeClients() (ExtendedClient, func()) { // Set this to `true` to output a trace of the API actions called // while running the tests const debug = false @@ -65,10 +66,7 @@ func fakeClients() (ExtendedClient, func()) { coreClient := corefake.NewSimpleClientset(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: defaultTestNamespace}}) fhrClient := fhrfake.NewSimpleClientset() hrClient := helmopfake.NewSimpleClientset() - dynamicClient := dynamicfake.NewSimpleDynamicClient(scheme) - crdClient := crdfake.NewSimpleClientset() shutdown := make(chan struct{}) - discoveryClient := MakeCachedDiscovery(coreClient.Discovery(), crdClient, shutdown) // Assigned here, since this is _also_ used by the (fake) // discovery client therein, and ultimately by @@ -77,7 +75,7 @@ func fakeClients() (ExtendedClient, func()) { coreClient.Fake.Resources = apiResources if debug { - for _, fake := range []*k8s_testing.Fake{&coreClient.Fake, &fhrClient.Fake, &hrClient.Fake, &dynamicClient.Fake} { + for _, fake := range []*k8s_testing.Fake{&coreClient.Fake, &fhrClient.Fake, &hrClient.Fake} { fake.PrependReactor("*", "*", func(action k8s_testing.Action) (bool, runtime.Object, error) { gvr := action.GetResource() fmt.Printf("[DEBUG] action: %s ns:%s %s/%s %s\n", action.GetVerb(), action.GetNamespace(), gvr.Group, gvr.Version, gvr.Resource) @@ -90,178 +88,25 @@ func fakeClients() (ExtendedClient, func()) { coreClient: coreClient, fluxHelmClient: fhrClient, helmOperatorClient: hrClient, - dynamicClient: dynamicClient, - discoveryClient: discoveryClient, } return ec, func() { close(shutdown) } } -// fakeApplier is an Applier that just forwards changeset operations -// to a dynamic client. It doesn't try to properly patch resources -// when that might be expected; it just overwrites them. But this is -// enough for checking whether sync operations succeeded and had the -// correct effect, which is either to "upsert", or delete, resources. -type fakeApplier struct { - dynamicClient dynamic.Interface - coreClient k8sclient.Interface - defaultNS string - commandRun bool -} - -func groupVersionResource(res *unstructured.Unstructured) schema.GroupVersionResource { - gvk := res.GetObjectKind().GroupVersionKind() - return schema.GroupVersionResource{Group: gvk.Group, Version: gvk.Version, Resource: strings.ToLower(gvk.Kind) + "s"} -} - -func (a fakeApplier) apply(_ log.Logger, cs changeSet, errored map[resource.ID]error) cluster.SyncError { - var errs []cluster.ResourceError - - operate := func(obj applyObject, cmd string) { - a.commandRun = true - var unstruct map[string]interface{} - if err := yaml.Unmarshal(obj.Payload, &unstruct); err != nil { - errs = append(errs, cluster.ResourceError{obj.ResourceID, obj.Source, err}) - return - } - res := &unstructured.Unstructured{Object: unstruct} - - // This is a special case trapdoor, for testing failure to - // apply a resource. - if errStr := res.GetAnnotations()["error"]; errStr != "" { - errs = append(errs, cluster.ResourceError{obj.ResourceID, obj.Source, fmt.Errorf(errStr)}) - return - } - - gvr := groupVersionResource(res) - c := a.dynamicClient.Resource(gvr) - // This is an approximation to what `kubectl` does in filling - // in the fallback namespace (from config). In the case of - // non-namespaced entities, it will be ignored by the fake - // client (FIXME: make sure of this). - apiRes := findAPIResource(gvr, a.coreClient.Discovery()) - if apiRes == nil { - panic("no APIResource found for " + gvr.String()) - } - - var dc dynamic.ResourceInterface = c - ns := res.GetNamespace() - if apiRes.Namespaced { - if ns == "" { - ns = a.defaultNS - res.SetNamespace(ns) - } - dc = c.Namespace(ns) - } - name := res.GetName() - - if cmd == "apply" { - _, err := dc.Get(name, metav1.GetOptions{}) - switch { - case errors.IsNotFound(err): - _, err = dc.Create(res, metav1.CreateOptions{}) - case err == nil: - _, err = dc.Update(res, metav1.UpdateOptions{}) - } - if err != nil { - errs = append(errs, cluster.ResourceError{obj.ResourceID, obj.Source, err}) - return - } - if res.GetKind() == "Namespace" { - // We also create namespaces in the core fake client since the dynamic client - // and core clients don't share resources - var ns corev1.Namespace - if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstruct, &ns); err != nil { - errs = append(errs, cluster.ResourceError{obj.ResourceID, obj.Source, err}) - return - } - _, err := a.coreClient.CoreV1().Namespaces().Get(ns.Name, metav1.GetOptions{}) - switch { - case errors.IsNotFound(err): - _, err = a.coreClient.CoreV1().Namespaces().Create(&ns) - case err == nil: - _, err = a.coreClient.CoreV1().Namespaces().Update(&ns) - } - if err != nil { - errs = append(errs, cluster.ResourceError{obj.ResourceID, obj.Source, err}) - return - } - } - - } else if cmd == "delete" { - if err := dc.Delete(name, &metav1.DeleteOptions{}); err != nil { - errs = append(errs, cluster.ResourceError{obj.ResourceID, obj.Source, err}) - return - } - if res.GetKind() == "Namespace" { - // We also create namespaces in the core fake client since the dynamic client - // and core clients don't share resources - if err := a.coreClient.CoreV1().Namespaces().Delete(res.GetName(), &metav1.DeleteOptions{}); err != nil { - errs = append(errs, cluster.ResourceError{obj.ResourceID, obj.Source, err}) - return - } - } - } else { - panic("unknown action: " + cmd) - } - } - - for _, obj := range cs.objs["delete"] { - operate(obj, "delete") - } - for _, obj := range cs.objs["apply"] { - operate(obj, "apply") - } - if len(errs) == 0 { - return nil - } - return errs -} - -func findAPIResource(gvr schema.GroupVersionResource, disco discovery.DiscoveryInterface) *metav1.APIResource { - groupVersion := gvr.Version - if gvr.Group != "" { - groupVersion = gvr.Group + "/" + groupVersion - } - reses, err := disco.ServerResourcesForGroupVersion(groupVersion) - if err != nil { - return nil - } - for _, res := range reses.APIResources { - if res.Name == gvr.Resource { - return &res - } - } - return nil -} - // --- -func setup(t *testing.T) (*Cluster, *fakeApplier, func()) { +func setup(t *testing.T) (*Cluster, func()) { clients, cancel := fakeClients() - applier := &fakeApplier{dynamicClient: clients.dynamicClient, coreClient: clients.coreClient, defaultNS: defaultTestNamespace} kube := &Cluster{ - applier: applier, - client: clients, - logger: log.NewLogfmtLogger(os.Stdout), - resourceExcludeList: []string{"*metrics.k8s.io/*", "webhook.certmanager.k8s.io/v1beta1/*"}, - } - return kube, applier, cancel -} - -func TestSyncNop(t *testing.T) { - kube, mock, cancel := setup(t) - defer cancel() - if err := kube.Sync(cluster.SyncSet{}); err != nil { - t.Errorf("%#v", err) - } - if mock.commandRun { - t.Error("expected no commands run") + engine: &fakeEngine{}, + client: clients, + logger: log.NewLogfmtLogger(os.Stdout), } + return kube, cancel } func TestSyncTolerateEmptyGroupVersion(t *testing.T) { - kube, _, cancel := setup(t) + kube, cancel := setup(t) defer cancel() // Add a GroupVersion without API Resources @@ -277,512 +122,3 @@ func TestSyncTolerateEmptyGroupVersion(t *testing.T) { err = kube.Sync(cluster.SyncSet{}) assert.NoError(t, err) } - -type failingDiscoveryClient struct { - discovery.DiscoveryInterface -} - -func (d *failingDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) { - return nil, errors.NewServiceUnavailable("") -} - -func TestSyncTolerateMetricsErrors(t *testing.T) { - kube, _, cancel := setup(t) - - // Replace the discovery client by one returning errors when asking for resources - cancel() - crdClient := crdfake.NewSimpleClientset() - shutdown := make(chan struct{}) - defer close(shutdown) - newDiscoveryClient := &failingDiscoveryClient{kube.client.coreClient.Discovery()} - kube.client.discoveryClient = MakeCachedDiscovery(newDiscoveryClient, crdClient, shutdown) - - // Check that syncing results in an error for groups other than metrics - fakeClient := kube.client.coreClient.(*corefake.Clientset) - fakeClient.Resources = []*metav1.APIResourceList{{GroupVersion: "foo.bar/v1"}} - err := kube.Sync(cluster.SyncSet{}) - assert.Error(t, err) - - // Check that syncing doesn't result in an error for a metrics group - kube.client.discoveryClient.(*cachedDiscovery).CachedDiscoveryInterface.Invalidate() - fakeClient.Resources = []*metav1.APIResourceList{{GroupVersion: "custom.metrics.k8s.io/v1"}} - err = kube.Sync(cluster.SyncSet{}) - assert.NoError(t, err) - - kube.client.discoveryClient.(*cachedDiscovery).CachedDiscoveryInterface.Invalidate() - fakeClient.Resources = []*metav1.APIResourceList{{GroupVersion: "webhook.certmanager.k8s.io/v1beta1"}} - err = kube.Sync(cluster.SyncSet{}) - assert.NoError(t, err) -} - -func TestSync(t *testing.T) { - const ns1 = `--- -apiVersion: v1 -kind: Namespace -metadata: - name: foobar -` - - const defs1 = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dep1 - namespace: foobar -` - - const defs2 = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dep2 - namespace: foobar -` - - const ns3 = `--- -apiVersion: v1 -kind: Namespace -metadata: - name: other -` - - const defs3 = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: dep3 - namespace: other -` - // checkSame is a check that a result returned from the cluster is - // the same as an expected. labels and annotations may be altered - // by the sync process; we'll look at the "spec" field as an - // indication of whether the resources are equivalent or not. - checkSame := func(t *testing.T, expected []byte, actual *unstructured.Unstructured) { - var expectedSpec struct{ Spec map[string]interface{} } - if err := yaml.Unmarshal(expected, &expectedSpec); err != nil { - t.Error(err) - return - } - if expectedSpec.Spec != nil { - assert.Equal(t, expectedSpec.Spec, actual.Object["spec"]) - } - } - - testDefaultNs := func(t *testing.T, kube *Cluster, defs, expectedAfterSync string, expectErrors bool, defaultNamespace string) { - saved := getKubeconfigDefaultNamespace - getKubeconfigDefaultNamespace = func() (string, error) { return defaultTestNamespace, nil } - defer func() { getKubeconfigDefaultNamespace = saved }() - namespacer, err := NewNamespacer(kube.client.coreClient.Discovery(), defaultNamespace) - if err != nil { - t.Fatal(err) - } - manifests := NewManifests(namespacer, log.NewLogfmtLogger(os.Stdout)) - - resources0, err := kresource.ParseMultidoc([]byte(defs), "before") - if err != nil { - t.Fatal(err) - } - - // Needed to get from KubeManifest to resource.Resource - resources, err := manifests.setEffectiveNamespaces(resources0) - if err != nil { - t.Fatal(err) - } - resourcesByID := map[string]resource.Resource{} - for _, r := range resources { - resourcesByID[r.ResourceID().String()] = r - } - err = sync.Sync("testset", resourcesByID, kube) - if !expectErrors && err != nil { - t.Error(err) - } - expected, err := kresource.ParseMultidoc([]byte(expectedAfterSync), "after") - if err != nil { - panic(err) - } - - // Now check that the resources were created - actual, err := kube.getAllowedGCMarkedResourcesInSyncSet("testset") - if err != nil { - t.Fatal(err) - } - - for id := range actual { - if _, ok := expected[id]; !ok { - t.Errorf("resource present after sync but not in resources applied: %q (present: %v)", id, actual) - if j, err := yaml.Marshal(actual[id].obj); err == nil { - println(string(j)) - } - continue - } - checkSame(t, expected[id].Bytes(), actual[id].obj) - } - for id := range expected { - if _, ok := actual[id]; !ok { - t.Errorf("resource supposed to be synced but not present: %q (present: %v)", id, actual) - } - // no need to compare values, since we already considered - // the intersection of actual and expected above. - } - } - test := func(t *testing.T, kube *Cluster, defs, expectedAfterSync string, expectErrors bool) { - testDefaultNs(t, kube, defs, expectedAfterSync, expectErrors, "") - } - - t.Run("sync adds and GCs resources", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - - // without GC on, resources persist if they are not mentioned in subsequent syncs. - test(t, kube, "", "", false) - test(t, kube, ns1+defs1, ns1+defs1, false) - test(t, kube, ns1+defs1+defs2, ns1+defs1+defs2, false) - test(t, kube, ns3+defs3, ns1+defs1+defs2+ns3+defs3, false) - - // Now with GC switched on. That means if we don't include a - // resource in a sync, it should be deleted. - kube.GC = true - test(t, kube, ns1+defs2+ns3+defs3, ns1+defs2+ns3+defs3, false) - test(t, kube, ns1+defs1+defs2, ns1+defs1+defs2, false) - test(t, kube, "", "", false) - }) - - t.Run("sync adds and GCs dry run", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - - // without GC on, resources persist if they are not mentioned in subsequent syncs. - test(t, kube, "", "", false) - test(t, kube, ns1+defs1, ns1+defs1, false) - test(t, kube, ns1+defs1+defs2, ns1+defs1+defs2, false) - test(t, kube, ns3+defs3, ns1+defs1+defs2+ns3+defs3, false) - - // with GC dry run the collect garbage routine is running but only logging results with out collecting any resources - kube.DryGC = true - test(t, kube, ns1+defs2+ns3+defs3, ns1+defs1+defs2+ns3+defs3, false) - test(t, kube, ns1+defs1+defs2, ns1+defs1+defs2+ns3+defs3, false) - test(t, kube, "", ns1+defs1+defs2+ns3+defs3, false) - }) - - t.Run("sync won't incorrectly delete non-namespaced resources", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - kube.GC = true - - const nsDef = ` -apiVersion: v1 -kind: Namespace -metadata: - name: bar-ns -` - test(t, kube, nsDef, nsDef, false) - }) - - t.Run("sync applies default namespace", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - kube.GC = true - - const depDef = ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: bar -` - const depDefNamespaced = ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: bar - namespace: system -` - const depDefAlreadyNamespaced = ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: bar - namespace: other -` - const ns1 = `--- -apiVersion: v1 -kind: Namespace -metadata: - name: foobar -` - defaultNs := "system" - testDefaultNs(t, kube, depDef, depDefNamespaced, false, defaultNs) - testDefaultNs(t, kube, depDefAlreadyNamespaced, depDefAlreadyNamespaced, false, defaultNs) - testDefaultNs(t, kube, ns1, ns1, false, defaultNs) - }) - - t.Run("sync won't delete resources that got the fallback namespace when created", func(t *testing.T) { - // NB: this tests the fake client implementation to some - // extent as well. It relies on it to reflect the kubectl - // behaviour of giving things that need a namespace some - // fallback (this would come from kubeconfig usually); and, - // for things that _don't_ have a namespace to have it - // stripped out. - kube, _, cancel := setup(t) - defer cancel() - kube.GC = true - const withoutNS = ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: depFallbackNS -` - const withNS = ` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: depFallbackNS - namespace: ` + defaultTestNamespace + ` -` - test(t, kube, withoutNS, withNS, false) - }) - - t.Run("sync won't delete resources whose garbage collection mark was copied to", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - kube.GC = true - - depName := "dep" - depNS := "foobar" - dep := fmt.Sprintf(`--- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: %s - namespace: %s -`, depName, depNS) - - // Add dep to the cluster through syncing - test(t, kube, ns1+dep, ns1+dep, false) - - // Add a copy of dep (including the GCmark label) with different name directly to the cluster - gvr := schema.GroupVersionResource{ - Group: "apps", - Version: "v1", - Resource: "deployments", - } - client := kube.client.dynamicClient.Resource(gvr).Namespace(depNS) - depActual, err := client.Get(depName, metav1.GetOptions{}) - assert.NoError(t, err) - depCopy := depActual.DeepCopy() - depCopyName := depName + "copy" - depCopy.SetName(depCopyName) - depCopyActual, err := client.Create(depCopy, metav1.CreateOptions{}) - assert.NoError(t, err) - - // Check that both dep and its copy have the same GCmark label - assert.Equal(t, depActual.GetName()+"copy", depCopyActual.GetName()) - assert.NotEmpty(t, depActual.GetLabels()[gcMarkLabel]) - assert.Equal(t, depActual.GetLabels()[gcMarkLabel], depCopyActual.GetLabels()[gcMarkLabel]) - - // Remove defs1 from the cluster through syncing - test(t, kube, "", "", false) - - // Check that defs1 is removed from the cluster but its copy isn't, due to having a different name - _, err = client.Get(depName, metav1.GetOptions{}) - assert.Error(t, err) - _, err = client.Get(depCopyName, metav1.GetOptions{}) - assert.NoError(t, err) - }) - - t.Run("sync won't delete if apply failed", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - kube.GC = true - - const defs1invalid = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep1 - annotations: - error: fail to apply this -` - test(t, kube, ns1+defs1, ns1+defs1, false) - test(t, kube, ns1+defs1invalid, ns1+defs1invalid, true) - }) - - t.Run("sync doesn't apply or delete manifests marked with ignore", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - kube.GC = true - - const dep1 = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep1 -spec: - metadata: - labels: {app: foo} -` - - const dep2 = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep2 - annotations: {flux.weave.works/ignore: "true"} -` - - // dep1 is created, but dep2 is ignored - test(t, kube, ns1+dep1+dep2, ns1+dep1, false) - - const dep1ignored = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep1 - annotations: - flux.weave.works/ignore: "true" -spec: - metadata: - labels: {app: bar} -` - // dep1 is not updated, but neither is it deleted - test(t, kube, ns1+dep1ignored+dep2, ns1+dep1, false) - }) - - t.Run("sync doesn't update a cluster resource marked with ignore", func(t *testing.T) { - const dep1 = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep1 -spec: - metadata: - labels: - app: original -` - kube, _, cancel := setup(t) - defer cancel() - // This just checks the starting assumption: dep1 exists in the cluster - test(t, kube, ns1+dep1, ns1+dep1, false) - - // Now we'll mark it as ignored _in the cluster_ (i.e., the - // equivalent of `kubectl annotate`) - dc := kube.client.dynamicClient - rc := dc.Resource(schema.GroupVersionResource{ - Group: "apps", - Version: "v1", - Resource: "deployments", - }) - res, err := rc.Namespace("foobar").Get("dep1", metav1.GetOptions{}) - if err != nil { - t.Fatal(err) - } - annots := res.GetAnnotations() - annots["flux.weave.works/ignore"] = "true" - res.SetAnnotations(annots) - if _, err = rc.Namespace("foobar").Update(res, metav1.UpdateOptions{}); err != nil { - t.Fatal(err) - } - - const mod1 = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep1 -spec: - metadata: - labels: - app: modified -` - // Check that dep1, which is marked ignore in the cluster, is - // neither updated or deleted - test(t, kube, ns1+mod1, ns1+dep1, false) - }) - - t.Run("sync doesn't update or delete a pre-existing resource marked with ignore", func(t *testing.T) { - kube, _, cancel := setup(t) - defer cancel() - - const existing = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep1 - annotations: {flux.weave.works/ignore: "true"} -spec: - metadata: - labels: {foo: original} -` - var dep1obj map[string]interface{} - err := yaml.Unmarshal([]byte(existing), &dep1obj) - assert.NoError(t, err) - dep1res := &unstructured.Unstructured{Object: dep1obj} - gvr := groupVersionResource(dep1res) - var ns1obj corev1.Namespace - err = yaml.Unmarshal([]byte(ns1), &ns1obj) - assert.NoError(t, err) - // Put the pre-existing resource in the cluster - _, err = kube.client.coreClient.CoreV1().Namespaces().Create(&ns1obj) - assert.NoError(t, err) - dc := kube.client.dynamicClient.Resource(gvr).Namespace(dep1res.GetNamespace()) - _, err = dc.Create(dep1res, metav1.CreateOptions{}) - assert.NoError(t, err) - - // Check that our resource-getting also sees the pre-existing resource - resources, err := kube.getAllowedResourcesBySelector("") - assert.NoError(t, err) - assert.Contains(t, resources, "foobar:deployment/dep1") - - // NB test checks the _synced_ resources, so this just asserts - // the precondition, that nothing is synced - test(t, kube, "", "", false) - - // .. but, our resource is still there. - r, err := dc.Get(dep1res.GetName(), metav1.GetOptions{}) - assert.NoError(t, err) - assert.NotNil(t, r) - - const update = `--- -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: foobar - name: dep1 -spec: - metadata: - labels: {foo: modified} -` - - // Check that it's not been synced (i.e., still not included in synced resources) - test(t, kube, update, "", false) - - // Check that it still exists, as created - r, err = dc.Get(dep1res.GetName(), metav1.GetOptions{}) - assert.NoError(t, err) - assert.NotNil(t, r) - checkSame(t, []byte(existing), r) - }) -} - -// ---- - -// TestApplyOrder checks that applyOrder works as expected. -func TestApplyOrder(t *testing.T) { - objs := []applyObject{ - {ResourceID: resource.MakeID("test", "Deployment", "deploy")}, - {ResourceID: resource.MakeID("test", "Secret", "secret")}, - {ResourceID: resource.MakeID("", "Namespace", "namespace")}, - } - sort.Sort(applyOrder(objs)) - for i, name := range []string{"namespace", "secret", "deploy"} { - _, _, objName := objs[i].ResourceID.Components() - if objName != name { - t.Errorf("Expected %q at position %d, got %q", name, i, objName) - } - } -}