├── hack ├── config │ ├── rbac │ │ ├── kustomization.yaml │ │ └── role.yaml │ ├── manager │ │ ├── namespace.yaml │ │ ├── serviceaccount.yaml │ │ ├── leader_election_role_binding.yaml │ │ ├── role_binding.yaml │ │ ├── kustomization.yaml │ │ ├── leader_election_role.yaml │ │ └── daemonset.yaml │ ├── crd │ │ ├── kustomization.yaml │ │ ├── kustomizeconfig.yaml │ │ └── upgrade.talos.dev_pools.yaml │ ├── examples │ │ ├── kustomization.yaml │ │ ├── env.yaml │ │ └── pools.yaml │ └── kustomization.yaml ├── boilerplate.go.txt └── test │ └── get-labels.sh ├── .gitignore ├── pkg ├── version │ ├── cache_interface.go │ ├── cache_interface_options.go │ ├── cache_v1alpha1.go │ └── version.go ├── upgrader │ ├── upgrader_interface.go │ ├── upgrade_policy_interface.go │ ├── upgrade_policy_serial.go │ ├── upgrade_policy_concurrent.go │ └── upgrader_v1alpha1.go ├── constants │ └── constants.go ├── channel │ ├── channel.go │ └── filter │ │ ├── filter_test.go │ │ └── filter.go ├── controllers │ ├── suite_test.go │ └── pool_controller.go └── registry │ └── registry.go ├── .conform.yaml ├── README.md ├── api └── v1alpha1 │ ├── groupversion_info.go │ ├── pool_types.go │ └── zz_generated.deepcopy.go ├── go.mod ├── Dockerfile ├── Makefile ├── .drone.yml ├── main.go └── go.sum /hack/config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - role.yaml 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _out 2 | hack/config/env.yaml 3 | talos-controller-manager 4 | -------------------------------------------------------------------------------- /hack/config/manager/namespace.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: talos-system 5 | -------------------------------------------------------------------------------- /hack/config/manager/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: talos-controller-manager 5 | -------------------------------------------------------------------------------- /hack/config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - upgrade.talos.dev_pools.yaml 3 | # +kubebuilder:scaffold:crdkustomizeresource 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /hack/config/examples/kustomization.yaml: -------------------------------------------------------------------------------- 1 | bases: 2 | - git@github.com:talos-systems/talos-controller-manager/hack/config?ref=master 3 | 4 | resources: 5 | - pools.yaml 6 | 7 | patchesStrategicMerge: 8 | - env.yaml 9 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | -------------------------------------------------------------------------------- /hack/config/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | namespace: talos-system 4 | commonLabels: 5 | app: talos-controller-manager 6 | bases: 7 | - crd 8 | - rbac 9 | - manager 10 | -------------------------------------------------------------------------------- /hack/config/examples/env.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: talos-controller-manager 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: talos-controller-manager 10 | env: 11 | - name: TALOS_TOKEN 12 | value: a2c4e6.1b3d5f7h9j1l3m5o 13 | -------------------------------------------------------------------------------- /hack/config/manager/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: talos-controller-manager 12 | -------------------------------------------------------------------------------- /hack/config/manager/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: talos-controller-manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: talos-controller-manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: talos-controller-manager 12 | -------------------------------------------------------------------------------- /hack/config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - namespace.yaml 5 | - role_binding.yaml 6 | - leader_election_role.yaml 7 | - leader_election_role_binding.yaml 8 | - serviceaccount.yaml 9 | - daemonset.yaml 10 | images: 11 | - name: docker.io/autonomy/talos-controller-manager 12 | newTag: latest 13 | -------------------------------------------------------------------------------- /pkg/version/cache_interface.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package version 6 | 7 | import ( 8 | "github.com/talos-systems/talos-controller-manager/pkg/channel" 9 | ) 10 | 11 | type Cache interface { 12 | Get(channel.Channel) (string, bool) 13 | Set(channel.Channel, string) 14 | } 15 | -------------------------------------------------------------------------------- /pkg/upgrader/upgrader_interface.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package upgrader 6 | 7 | import ( 8 | corev1 "k8s.io/api/core/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 10 | ) 11 | 12 | type Upgrader interface { 13 | Upgrade(reconcile.Request, corev1.Node, string, bool) error 14 | } 15 | -------------------------------------------------------------------------------- /pkg/upgrader/upgrade_policy_interface.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package upgrader 6 | 7 | import ( 8 | corev1 "k8s.io/api/core/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 10 | ) 11 | 12 | type UpgradePolicy interface { 13 | Run(reconcile.Request, corev1.NodeList, string) error 14 | } 15 | -------------------------------------------------------------------------------- /pkg/version/cache_interface_options.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package version 6 | 7 | type GetOptions struct{} 8 | 9 | type GetOption func(*GetOptions) 10 | 11 | func NewGetOptions(setters ...GetOption) *GetOptions { 12 | opts := &GetOptions{} 13 | 14 | for _, setter := range setters { 15 | setter(opts) 16 | } 17 | 18 | return opts 19 | } 20 | -------------------------------------------------------------------------------- /pkg/constants/constants.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package constants 6 | 7 | const ( 8 | DefaultRegistry = "https://registry-1.docker.io" 9 | 10 | DefaultRepository = "autonomy/installer" 11 | 12 | InstallerVersionLabel = "alpha.talos.dev/version" 13 | ) 14 | 15 | // Pool labels 16 | 17 | const ( 18 | V1Alpha1PoolLabel = "v1alpha1.upgrade.talos.dev/pool" 19 | ) 20 | -------------------------------------------------------------------------------- /hack/config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | group: apiextensions.k8s.io 8 | path: spec/conversion/webhookClientConfig/service/name 9 | 10 | namespace: 11 | - kind: CustomResourceDefinition 12 | group: apiextensions.k8s.io 13 | path: spec/conversion/webhookClientConfig/service/namespace 14 | create: false 15 | 16 | varReference: 17 | - path: metadata/annotations 18 | -------------------------------------------------------------------------------- /hack/config/manager/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - "" 21 | resources: 22 | - configmaps/status 23 | verbs: 24 | - get 25 | - update 26 | - patch 27 | - apiGroups: 28 | - "" 29 | resources: 30 | - events 31 | verbs: 32 | - create 33 | -------------------------------------------------------------------------------- /hack/test/get-labels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | IMAGE=autonomy/installer 4 | TAG=latest 5 | 6 | TOKEN=$(curl -s "https://auth.docker.io/token?scope=repository:$IMAGE:pull&service=registry.docker.io" | jq -r .token) 7 | echo $TOKEN 8 | CONFIG_DIGEST=$(curl -s -H"Accept: application/vnd.docker.distribution.manifest.v2+json" -H"Authorization: Bearer $TOKEN" "https://registry-1.docker.io/v2/$IMAGE/manifests/$TAG" | jq -r .config.digest) 9 | echo $CONFIG_DIGEST 10 | 11 | LABELS=$(curl -sL -H"Authorization: Bearer $TOKEN" "https://registry-1.docker.io/v2/$IMAGE/blobs/$CONFIG_DIGEST" | jq -r .config.Labels) 12 | echo $LABELS 13 | -------------------------------------------------------------------------------- /hack/config/examples/pools.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: upgrade.talos.dev/v1alpha1 2 | kind: Pool 3 | metadata: 4 | name: serial-latest 5 | namespace: talos-system 6 | spec: 7 | channel: latest 8 | registry: https://registry-1.docker.io 9 | repository: autonomy/installer 10 | concurrency: 1 11 | onFailure: Pause 12 | checkInterval: 2m 13 | --- 14 | apiVersion: upgrade.talos.dev/v1alpha1 15 | kind: Pool 16 | metadata: 17 | name: concurrent-latest 18 | namespace: talos-system 19 | spec: 20 | channel: latest 21 | registry: https://registry-1.docker.io 22 | repository: autonomy/installer 23 | concurrency: 3 24 | onFailure: Retry 25 | checkInterval: 2m 26 | -------------------------------------------------------------------------------- /pkg/upgrader/upgrade_policy_serial.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package upgrader 6 | 7 | import ( 8 | corev1 "k8s.io/api/core/v1" 9 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 10 | ) 11 | 12 | type SerialPolicy struct { 13 | Upgrader 14 | } 15 | 16 | func (policy SerialPolicy) Run(req reconcile.Request, nodes corev1.NodeList, version string, inProgress bool) error { 17 | for _, node := range nodes.Items { 18 | if err := policy.Upgrade(req, node, version, inProgress); err != nil { 19 | return err 20 | } 21 | } 22 | 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /pkg/channel/channel.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package channel 6 | 7 | import "fmt" 8 | 9 | const ( 10 | LatestChannel = "latest" 11 | EdgeChannel = "edge" 12 | AlphaChannel = "alpha" 13 | BetaChannel = "beta" 14 | StableChannel = "stable" 15 | ) 16 | 17 | type Channel = string 18 | 19 | type InvalidChannelError struct { 20 | value string 21 | } 22 | 23 | func NewInvalidChannelError(c string) InvalidChannelError { 24 | return InvalidChannelError{c} 25 | } 26 | 27 | func (i InvalidChannelError) Error() string { 28 | return fmt.Sprintf("invalid channel: %s", i.value) 29 | } 30 | -------------------------------------------------------------------------------- /.conform.yaml: -------------------------------------------------------------------------------- 1 | policies: 2 | - type: commit 3 | spec: 4 | dco: true 5 | gpg: false 6 | spellcheck: 7 | locale: US 8 | maximumOfOneCommit: true 9 | header: 10 | length: 89 11 | imperative: true 12 | case: lower 13 | invalidLastCharacters: . 14 | body: 15 | required: true 16 | conventional: 17 | types: ['chore', 'docs', 'perf', 'refactor', 'style', 'test', 'release'] 18 | scopes: ['*'] 19 | - type: license 20 | spec: 21 | skipPaths: 22 | - .git/ 23 | includeSuffixes: 24 | - .go 25 | excludeSuffixes: 26 | - .pb.go 27 | - .deepcopy.go 28 | header: | 29 | // This Source Code Form is subject to the terms of the Mozilla Public 30 | // License, v. 2.0. If a copy of the MPL was not distributed with this 31 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 32 | -------------------------------------------------------------------------------- /hack/config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | kind: ClusterRole 5 | metadata: 6 | creationTimestamp: null 7 | name: talos-controller-manager-role 8 | rules: 9 | - apiGroups: 10 | - "" 11 | resources: 12 | - endpoints 13 | verbs: 14 | - get 15 | - apiGroups: 16 | - "" 17 | resources: 18 | - nodes 19 | verbs: 20 | - get 21 | - list 22 | - patch 23 | - update 24 | - watch 25 | - apiGroups: 26 | - coordination.k8s.io 27 | resources: 28 | - leases 29 | verbs: 30 | - create 31 | - delete 32 | - get 33 | - list 34 | - patch 35 | - update 36 | - watch 37 | - apiGroups: 38 | - upgrade.talos.dev 39 | resources: 40 | - pools 41 | verbs: 42 | - create 43 | - delete 44 | - get 45 | - list 46 | - patch 47 | - update 48 | - watch 49 | - apiGroups: 50 | - upgrade.talos.dev 51 | resources: 52 | - pools/status 53 | verbs: 54 | - get 55 | - patch 56 | - update 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # talos-controller-manager 2 | 3 | ## Getting Started 4 | 5 | ```bash 6 | kubectl label node -l node-role.kubernetes.io/master='' v1alpha1.upgrade.talos.dev/pool=serial-latest 7 | kubectl label node -l node-role.kubernetes.io/worker='' v1alpha1.upgrade.talos.dev/pool=concurrent-latest 8 | ``` 9 | 10 | ```bash 11 | export TOKEN= 12 | cat <./hack/config/examples/env.yaml 13 | apiVersion: apps/v1 14 | kind: DaemonSet 15 | metadata: 16 | name: talos-controller-manager 17 | spec: 18 | template: 19 | spec: 20 | containers: 21 | - name: talos-controller-manager 22 | env: 23 | - name: TALOS_TOKEN 24 | value: $TOKEN 25 | EOF 26 | ``` 27 | 28 | ```bash 29 | kubectl apply -k ./hack/config/examples 30 | ``` 31 | 32 | ```bash 33 | kubectl get pods -n talos-system 34 | ``` 35 | 36 | ```bash 37 | kubectl logs -n talos-system -f $(kubectl get lease -n talos-system talos-controller-manager -o jsonpath='{.spec.holderIdentity}') 38 | ``` 39 | -------------------------------------------------------------------------------- /api/v1alpha1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | // Package v1alpha1 contains API Schema definitions for the pool v1alpha1 API group 6 | // +kubebuilder:object:generate=true 7 | // +groupName=upgrade.talos.dev 8 | package v1alpha1 9 | 10 | import ( 11 | "k8s.io/apimachinery/pkg/runtime/schema" 12 | "sigs.k8s.io/controller-runtime/pkg/scheme" 13 | ) 14 | 15 | var ( 16 | // GroupVersion is group version used to register these objects 17 | GroupVersion = schema.GroupVersion{Group: "upgrade.talos.dev", Version: "v1alpha1"} 18 | 19 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 20 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 21 | 22 | // AddToScheme adds the types in this group-version to the given scheme. 23 | AddToScheme = SchemeBuilder.AddToScheme 24 | ) 25 | -------------------------------------------------------------------------------- /hack/config/manager/daemonset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: DaemonSet 3 | metadata: 4 | name: talos-controller-manager 5 | labels: 6 | app: talos-controller-manager 7 | spec: 8 | selector: 9 | matchLabels: 10 | app: talos-controller-manager 11 | updateStrategy: 12 | type: RollingUpdate 13 | template: 14 | metadata: 15 | annotations: 16 | labels: 17 | app: talos-controller-manager 18 | spec: 19 | containers: 20 | - name: talos-controller-manager 21 | image: docker.io/autonomy/talos-controller-manager:latest 22 | imagePullPolicy: Always 23 | command: 24 | - /talos-controller-manager 25 | restartPolicy: Always 26 | serviceAccount: talos-controller-manager 27 | serviceAccountName: talos-controller-manager 28 | nodeSelector: 29 | node-role.kubernetes.io/master: "" 30 | tolerations: 31 | - effect: NoSchedule 32 | key: node-role.kubernetes.io/master 33 | operator: Exists 34 | -------------------------------------------------------------------------------- /pkg/version/cache_v1alpha1.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package version 6 | 7 | import ( 8 | "sync" 9 | 10 | "github.com/talos-systems/talos-controller-manager/pkg/channel" 11 | ) 12 | 13 | type VersionMap map[channel.Channel]string 14 | 15 | type V1Alpha1 struct { 16 | v VersionMap 17 | 18 | mu sync.Mutex 19 | } 20 | 21 | func (v1alpha1 *V1Alpha1) Get(channel channel.Channel) (string, bool) { 22 | v1alpha1.mu.Lock() 23 | defer v1alpha1.mu.Unlock() 24 | 25 | if v1alpha1.v == nil { 26 | v1alpha1.v = VersionMap{} 27 | } 28 | 29 | version, ok := v1alpha1.v[channel] 30 | 31 | return version, ok 32 | } 33 | 34 | func (v1alpha1 *V1Alpha1) Set(channel channel.Channel, value string) { 35 | v1alpha1.mu.Lock() 36 | defer v1alpha1.mu.Unlock() 37 | 38 | if v1alpha1.v == nil { 39 | v1alpha1.v = VersionMap{} 40 | } 41 | 42 | v1alpha1.v[channel] = value 43 | } 44 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/talos-systems/talos-controller-manager 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/blang/semver v3.5.0+incompatible 7 | github.com/docker/distribution v2.7.1+incompatible 8 | github.com/docker/go-metrics v0.0.1 // indirect 9 | github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect 10 | github.com/go-logr/logr v0.1.0 11 | github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect 12 | github.com/gorilla/mux v1.7.3 // indirect 13 | github.com/hashicorp/go-multierror v1.0.0 14 | github.com/hashicorp/golang-lru v0.5.3 // indirect 15 | github.com/imdario/mergo v0.3.8 // indirect 16 | github.com/onsi/ginkgo v1.10.3 17 | github.com/onsi/gomega v1.7.1 18 | github.com/opencontainers/go-digest v1.0.0-rc1 19 | github.com/pkg/errors v0.8.1 20 | github.com/prometheus/client_golang v1.2.1 // indirect 21 | github.com/talos-systems/talos v0.4.0-alpha.2.0.20200122012516-e7749d2e8fce 22 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect 23 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 // indirect 24 | google.golang.org/appengine v1.6.5 // indirect 25 | google.golang.org/grpc v1.26.0 26 | k8s.io/api v0.17.0 27 | k8s.io/apiextensions-apiserver v0.0.0-20191108071732-08c66a398f44 // indirect 28 | k8s.io/apimachinery v0.17.0 29 | k8s.io/client-go v0.17.0 30 | sigs.k8s.io/controller-runtime v0.3.1-0.20191105233659-81842d0e78f7 31 | ) 32 | -------------------------------------------------------------------------------- /pkg/controllers/suite_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package controllers 6 | 7 | import ( 8 | "path/filepath" 9 | "testing" 10 | 11 | . "github.com/onsi/ginkgo" 12 | . "github.com/onsi/gomega" 13 | 14 | poolv1alpha1 "github.com/talos-systems/talos-controller-manager/api/v1alpha1" 15 | "k8s.io/client-go/kubernetes/scheme" 16 | "k8s.io/client-go/rest" 17 | "sigs.k8s.io/controller-runtime/pkg/client" 18 | "sigs.k8s.io/controller-runtime/pkg/envtest" 19 | logf "sigs.k8s.io/controller-runtime/pkg/log" 20 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 21 | // +kubebuilder:scaffold:imports 22 | ) 23 | 24 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to 25 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 26 | 27 | var cfg *rest.Config 28 | var k8sClient client.Client 29 | var testEnv *envtest.Environment 30 | 31 | func TestAPIs(t *testing.T) { 32 | RegisterFailHandler(Fail) 33 | 34 | RunSpecsWithDefaultAndCustomReporters(t, 35 | "Controller Suite", 36 | []Reporter{envtest.NewlineReporter{}}) 37 | } 38 | 39 | var _ = BeforeSuite(func(done Done) { 40 | logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) 41 | 42 | By("bootstrapping test environment") 43 | testEnv = &envtest.Environment{ 44 | CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, 45 | } 46 | 47 | var err error 48 | cfg, err = testEnv.Start() 49 | Expect(err).ToNot(HaveOccurred()) 50 | Expect(cfg).ToNot(BeNil()) 51 | 52 | err = poolv1alpha1.AddToScheme(scheme.Scheme) 53 | Expect(err).NotTo(HaveOccurred()) 54 | 55 | // +kubebuilder:scaffold:scheme 56 | 57 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) 58 | Expect(err).ToNot(HaveOccurred()) 59 | Expect(k8sClient).ToNot(BeNil()) 60 | 61 | close(done) 62 | }, 60) 63 | 64 | var _ = AfterSuite(func() { 65 | By("tearing down the test environment") 66 | err := testEnv.Stop() 67 | Expect(err).ToNot(HaveOccurred()) 68 | }) 69 | -------------------------------------------------------------------------------- /pkg/upgrader/upgrade_policy_concurrent.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package upgrader 6 | 7 | import ( 8 | "github.com/go-logr/logr" 9 | "github.com/hashicorp/go-multierror" 10 | corev1 "k8s.io/api/core/v1" 11 | ctrl "sigs.k8s.io/controller-runtime" 12 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 13 | ) 14 | 15 | type ConcurrentPolicy struct { 16 | Upgrader 17 | 18 | Concurrency int 19 | 20 | log logr.Logger 21 | } 22 | 23 | type Job struct { 24 | req reconcile.Request 25 | node corev1.Node 26 | version string 27 | inProgress bool 28 | } 29 | 30 | type Result struct { 31 | job Job 32 | err error 33 | } 34 | 35 | func NewConcurrentPolicy(u Upgrader, c int) ConcurrentPolicy { 36 | return ConcurrentPolicy{ 37 | Upgrader: u, 38 | Concurrency: c, 39 | log: ctrl.Log.WithName("policy").WithName("Concurrent"), 40 | } 41 | } 42 | 43 | func (policy ConcurrentPolicy) Run(req reconcile.Request, nodes corev1.NodeList, version string, inProgress bool) error { 44 | jobs := make(chan Job, policy.Concurrency) 45 | results := make(chan Result, len(nodes.Items)) 46 | 47 | for w := 0; w < policy.Concurrency; w++ { 48 | go policy.worker(w, jobs, results) 49 | } 50 | 51 | for _, node := range nodes.Items { 52 | jobs <- Job{req, node, version, inProgress} 53 | } 54 | 55 | close(jobs) 56 | 57 | var result *multierror.Error 58 | 59 | for a := 0; a < len(nodes.Items); a++ { 60 | r := <-results 61 | if r.err != nil { 62 | result = multierror.Append(result, r.err) 63 | } 64 | } 65 | 66 | return result.ErrorOrNil() 67 | } 68 | 69 | func (policy ConcurrentPolicy) worker(id int, jobs <-chan Job, results chan<- Result) { 70 | for j := range jobs { 71 | policy.log.Info("assigned worker to node", "id", id, "node", j.node.Name) 72 | 73 | if err := policy.Upgrade(j.req, j.node, j.version, j.inProgress); err != nil { 74 | results <- Result{j, err} 75 | } 76 | 77 | results <- Result{j, nil} 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax = docker/dockerfile-upstream:1.1.4-experimental 2 | 3 | FROM golang:1.13 AS build 4 | ENV GO111MODULE on 5 | ENV GOPROXY https://proxy.golang.org 6 | ENV CGO_ENABLED 0 7 | WORKDIR /tmp 8 | RUN go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.4 9 | WORKDIR /src 10 | COPY ./go.mod ./ 11 | COPY ./go.sum ./ 12 | RUN go mod download 13 | RUN go mod verify 14 | COPY ./main.go ./main.go 15 | COPY ./api ./api 16 | COPY ./pkg ./pkg 17 | COPY ./hack ./hack 18 | RUN go list -mod=readonly all >/dev/null 19 | RUN ! go mod tidy -v 2>&1 | grep . 20 | 21 | FROM build AS manifests-build 22 | RUN controller-gen rbac:roleName=talos-controller-manager-role crd paths="./..." output:rbac:artifacts:config=hack/config/rbac output:crd:artifacts:config=hack/config/crd 23 | FROM scratch AS manifests 24 | COPY --from=manifests-build /src/hack/config/crd /hack/config/crd 25 | COPY --from=manifests-build /src/hack/config/manager /hack/config/manager 26 | COPY --from=manifests-build /src/hack/config/rbac /hack/config/rbac 27 | 28 | FROM build AS generate-build 29 | RUN controller-gen object:headerFile=./hack/boilerplate.go.txt paths="./..." 30 | FROM scratch AS generate 31 | COPY --from=generate-build /src/api /api 32 | 33 | FROM k8s.gcr.io/hyperkube:v1.17.0 AS release-build 34 | RUN apt update -y \ 35 | && apt install -y curl \ 36 | && curl -LO https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.4.0/kustomize_v3.4.0_linux_amd64.tar.gz \ 37 | && tar -xf kustomize_v3.4.0_linux_amd64.tar.gz -C /usr/local/bin \ 38 | && rm kustomize_v3.4.0_linux_amd64.tar.gz 39 | COPY ./hack ./hack 40 | ARG TAG 41 | RUN cd hack/config/manager \ 42 | && kustomize edit set image docker.io/autonomy/talos-controller-manager:$TAG \ 43 | && cd - \ 44 | && kubectl kustomize hack/config >/release.yaml 45 | FROM scratch AS release 46 | COPY --from=release-build /release.yaml /release.yaml 47 | 48 | FROM build AS binary 49 | RUN --mount=type=cache,target=/root/.cache/go-build GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o /talos-controller-manager 50 | RUN chmod +x /talos-controller-manager 51 | 52 | FROM scratch AS container 53 | COPY --from=docker.io/autonomy/ca-certificates:febbf49 / / 54 | COPY --from=docker.io/autonomy/fhs:febbf49 / / 55 | COPY --from=binary /talos-controller-manager /talos-controller-manager 56 | ENTRYPOINT [ "/talos-controller-manager" ] 57 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | REGISTRY ?= docker.io 2 | USERNAME ?= autonomy 3 | SHA ?= $(shell git describe --match=none --always --abbrev=8 --dirty) 4 | TAG ?= $(shell git describe --tag --always --dirty) 5 | BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) 6 | REGISTRY_AND_USERNAME := $(REGISTRY)/$(USERNAME) 7 | 8 | ARTIFACTS := _out 9 | 10 | BUILD := docker buildx build 11 | PLATFORM ?= linux/amd64 12 | PROGRESS ?= auto 13 | PUSH ?= false 14 | COMMON_ARGS := --file=Dockerfile 15 | COMMON_ARGS += --progress=$(PROGRESS) 16 | COMMON_ARGS += --platform=$(PLATFORM) 17 | 18 | all: manifests container 19 | 20 | .PHONY: help 21 | help: ## This help menu. 22 | @grep -E '^[a-zA-Z%_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 23 | 24 | target-%: ## Builds the specified target defined in the Dockerfile. The build result will only remain in the build cache. 25 | @$(BUILD) \ 26 | --target=$* \ 27 | $(COMMON_ARGS) \ 28 | $(TARGET_ARGS) . 29 | 30 | local-%: ## Builds the specified target defined in the Dockerfile using the local output type. The build result will be output to the specified local destination. 31 | @$(MAKE) target-$* TARGET_ARGS="--output=type=local,dest=$(DEST) $(TARGET_ARGS)" 32 | 33 | docker-%: ## Builds the specified target defined in the Dockerfile using the docker output type. The build result will be loaded into docker. 34 | @$(MAKE) target-$* TARGET_ARGS="--tag $(REGISTRY_AND_USERNAME)/talos-controller-manager:$(TAG) $(TARGET_ARGS)" 35 | 36 | .PHONY: generate 37 | generate: ## Generates source code from protobuf definitions. 38 | @$(MAKE) local-$@ DEST=./ 39 | 40 | .PHONY: container 41 | container: generate ## Build a container image. 42 | @$(MAKE) docker-$@ TARGET_ARGS="--push=$(PUSH)" 43 | 44 | .PHONY: manifests 45 | manifests: ## Generate manifests (e.g. CRD, RBAC, etc.). 46 | @$(MAKE) local-$@ DEST=./ 47 | 48 | .PHONY: release 49 | release: manifests container ## Create the release YAML. The build result will be ouput to the specified local destination. 50 | @$(MAKE) local-$@ DEST=./$(ARTIFACTS) 51 | 52 | .PHONY: deploy 53 | deploy: manifests ## Deploy to a cluster. This is for testing purposes only. 54 | kubectl apply -k hack/config 55 | 56 | .PHONY: destroy 57 | destroy: ## Remove from a cluster. This is for testing purposes only. 58 | kubectl delete -k hack/config 59 | 60 | .PHONY: clean 61 | clean: 62 | @rm -rf $(ARTIFACTS) 63 | -------------------------------------------------------------------------------- /pkg/version/version.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package version 6 | 7 | import ( 8 | "log" 9 | "sync" 10 | "time" 11 | 12 | "github.com/talos-systems/talos-controller-manager/pkg/channel" 13 | "github.com/talos-systems/talos-controller-manager/pkg/channel/filter" 14 | "github.com/talos-systems/talos-controller-manager/pkg/registry" 15 | ) 16 | 17 | type Version struct { 18 | Cache 19 | 20 | synced chan struct{} 21 | } 22 | 23 | func NewVersion(cache Cache) *Version { 24 | return &Version{ 25 | Cache: cache, 26 | synced: make(chan struct{}, 1), 27 | } 28 | } 29 | 30 | func (v Version) WaitForCacheSync() bool { 31 | select { 32 | case <-v.synced: 33 | return true 34 | case <-time.After(time.Minute): 35 | return false 36 | } 37 | } 38 | 39 | func (v Version) Run(reg, repository string, channels []channel.Channel) error { 40 | repo, err := registry.New(reg, repository) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | for { 46 | tags, err := repo.Tags() 47 | if err != nil { 48 | return err 49 | } 50 | 51 | var wg sync.WaitGroup 52 | 53 | wg.Add(len(channels)) 54 | 55 | for _, channel := range channels { 56 | go func(c string) { 57 | defer wg.Done() 58 | v.discover(c, reg, repository, tags) 59 | }(channel) 60 | } 61 | 62 | wg.Wait() 63 | 64 | v.synced <- struct{}{} 65 | 66 | time.Sleep(5 * time.Minute) 67 | } 68 | } 69 | 70 | func (v Version) discover(c, reg, repo string, tags []string) { 71 | var found *string 72 | switch c { 73 | case channel.LatestChannel: 74 | found = filter.FilterTagsFor(channel.LatestChannel, reg, repo) 75 | case channel.EdgeChannel: 76 | found = filter.FilterTagsFor(channel.EdgeChannel, reg, repo) 77 | case channel.AlphaChannel, channel.BetaChannel, channel.StableChannel: 78 | found = filter.FilterSemver(c, tags) 79 | default: 80 | log.Printf("%v", channel.NewInvalidChannelError(c)) 81 | return 82 | } 83 | 84 | if found == nil { 85 | return 86 | } 87 | 88 | if *found == "" { 89 | return 90 | } 91 | 92 | // No change in version. 93 | version, ok := v.Get(c) 94 | if ok && version == *found { 95 | return 96 | } 97 | 98 | // A new tag has been detected, update the cache. 99 | v.Set(c, *found) 100 | } 101 | -------------------------------------------------------------------------------- /api/v1alpha1/pool_types.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package v1alpha1 6 | 7 | import ( 8 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 | ) 10 | 11 | // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. 12 | 13 | // PoolSpec defines the desired state of Pool 14 | type PoolSpec struct { 15 | Channel string `json:"channel,omitempty"` 16 | Version string `json:"version,omitempty"` 17 | Registry string `json:"registry,omitempty"` 18 | Repository string `json:"repository,omitempty"` 19 | Concurrency int `json:"concurrency,omitempty"` 20 | FailurePolicy string `json:"onFailure,omitempty"` 21 | CheckInterval *metav1.Duration `json:"checkInterval,omitempty"` 22 | } 23 | 24 | // PoolStatus defines the observed state of Pool 25 | type PoolStatus struct { 26 | Size int `json:"size,omitempty"` 27 | NextRun metav1.Time `json:"nextRun,omitempty"` 28 | InProgress string `json:"inProgress,omitempty"` 29 | Version string `json:"version,omitempty"` 30 | } 31 | 32 | // +kubebuilder:object:root=true 33 | // +kubebuilder:resource:path=pools,scope=Cluster 34 | 35 | // Pool is the Schema for the pools API 36 | // See https://book.kubebuilder.io/reference/markers/crd.html 37 | // +kubebuilder:printcolumn:name="Channel",type="string",JSONPath=".spec.channel",description="the pool's upgrade channel" 38 | // +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".status.version",description="the pool's target version" 39 | // +kubebuilder:printcolumn:name="Size",type="integer",JSONPath=".status.size",description="the number of nodes in the pool" 40 | // +kubebuilder:printcolumn:name="Concurrency",type="string",JSONPath=".spec.concurrency",description="the pool's maximum number of concurrent upgrades" 41 | // +kubebuilder:printcolumn:name="Next Run",type="string",format="date-time",JSONPath=".status.nextRun",description="when the next upgrade attempt will be made (UTC time standard)" 42 | // +kubebuilder:printcolumn:name="In Progress",type="string",JSONPath=".status.inProgress",description="the nodes in the pool that are currently in progress of upgrading" 43 | type Pool struct { 44 | metav1.TypeMeta `json:",inline"` 45 | metav1.ObjectMeta `json:"metadata,omitempty"` 46 | 47 | Spec PoolSpec `json:"spec,omitempty"` 48 | Status PoolStatus `json:"status,omitempty"` 49 | } 50 | 51 | // +kubebuilder:object:root=true 52 | 53 | // PoolList contains a list of Pool 54 | type PoolList struct { 55 | metav1.TypeMeta `json:",inline"` 56 | metav1.ListMeta `json:"metadata,omitempty"` 57 | Items []Pool `json:"items"` 58 | } 59 | 60 | func init() { 61 | SchemeBuilder.Register(&Pool{}, &PoolList{}) 62 | } 63 | -------------------------------------------------------------------------------- /pkg/channel/filter/filter_test.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package filter 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/talos-systems/talos-controller-manager/pkg/channel" 11 | ) 12 | 13 | func TestFilterSemver(t *testing.T) { 14 | type args struct { 15 | ch string 16 | tags []string 17 | } 18 | tests := []struct { 19 | name string 20 | args args 21 | wantTarget *string 22 | }{ 23 | { 24 | name: "latest version", 25 | args: args{ 26 | ch: channel.LatestChannel, 27 | tags: []string{ 28 | "v0.1.0", 29 | "v0.1.0-STRING", 30 | "v0.2.0-alpha.0-STRING", 31 | "v0.2.0-alpha.1", 32 | "v0.2.0-alpha.1-STRING", 33 | }, 34 | }, 35 | wantTarget: ptr("v0.2.0-alpha.1-STRING"), 36 | }, 37 | { 38 | name: "alpha version", 39 | args: args{ 40 | ch: channel.AlphaChannel, 41 | tags: []string{ 42 | "v0.1.0", 43 | "v0.1.0-STRING", 44 | "v0.2.0-alpha.0-STRING", 45 | "v0.2.0-alpha.1", 46 | }, 47 | }, 48 | wantTarget: ptr("v0.2.0-alpha.1"), 49 | }, 50 | { 51 | name: "alpha version older than latest stable", 52 | args: args{ 53 | ch: channel.AlphaChannel, 54 | tags: []string{ 55 | "v0.1.0", 56 | "v0.1.0-STRING", 57 | "v0.2.0-alpha.0-STRING", 58 | "v0.2.0-alpha.1", 59 | "v0.2.0", 60 | }, 61 | }, 62 | wantTarget: ptr("v0.2.0"), 63 | }, 64 | { 65 | name: "beta version", 66 | args: args{ 67 | ch: channel.BetaChannel, 68 | tags: []string{ 69 | "v0.1.0", 70 | "v0.1.0-STRING", 71 | "v0.2.0-alpha.0-STRING", 72 | "v0.2.0-alpha.1", 73 | "v0.2.0-beta.0-STRING", 74 | "v0.2.0-beta.1", 75 | }, 76 | }, 77 | wantTarget: ptr("v0.2.0-beta.1"), 78 | }, 79 | { 80 | name: "beta version older than latest stable", 81 | args: args{ 82 | ch: channel.BetaChannel, 83 | tags: []string{ 84 | "v0.1.0", 85 | "v0.1.0-STRING", 86 | "v0.2.0-alpha.0-STRING", 87 | "v0.2.0-alpha.1", 88 | "v0.2.0-beta.0-STRING", 89 | "v0.2.0-beta.1", 90 | "v0.3.0", 91 | "v0.4.0-alpha.0", 92 | }, 93 | }, 94 | wantTarget: ptr("v0.3.0"), 95 | }, 96 | { 97 | name: "stable version", 98 | args: args{ 99 | ch: channel.StableChannel, 100 | tags: []string{ 101 | "v0.1.0", 102 | "v0.1.0-STRING", 103 | "v0.2.0-alpha.0-STRING", 104 | "v0.2.0-alpha.1", 105 | }, 106 | }, 107 | wantTarget: ptr("v0.1.0"), 108 | }, 109 | } 110 | for _, tt := range tests { 111 | t.Run(tt.name, func(t *testing.T) { 112 | if gotTarget := FilterSemver(tt.args.ch, tt.args.tags); *gotTarget != *tt.wantTarget { 113 | t.Errorf("FilterSemver() = %v, want %v", *gotTarget, *tt.wantTarget) 114 | } 115 | }) 116 | } 117 | } 118 | 119 | func ptr(s string) *string { 120 | return &s 121 | } 122 | -------------------------------------------------------------------------------- /pkg/channel/filter/filter.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package filter 6 | 7 | import ( 8 | "log" 9 | 10 | "github.com/talos-systems/talos-controller-manager/pkg/channel" 11 | "github.com/talos-systems/talos-controller-manager/pkg/constants" 12 | "github.com/talos-systems/talos-controller-manager/pkg/registry" 13 | 14 | "github.com/blang/semver" 15 | digest "github.com/opencontainers/go-digest" 16 | ) 17 | 18 | func FilterTagsFor(s, reg, repository string) (target *string) { 19 | repo, err := registry.New(reg, repository) 20 | if err != nil { 21 | log.Println(err) 22 | return nil 23 | } 24 | 25 | manifest, err := repo.Manifest(s) 26 | if err != nil { 27 | log.Println(err) 28 | return nil 29 | } 30 | 31 | dgst := digest.NewDigestFromHex( 32 | manifest.Digest.Algorithm().String(), 33 | manifest.Digest.Encoded(), 34 | ) 35 | 36 | config, err := repo.Configuration(dgst) 37 | if err != nil { 38 | log.Println(err) 39 | return nil 40 | } 41 | 42 | t := config.Config.Labels[constants.InstallerVersionLabel] 43 | target = &t 44 | 45 | return target 46 | } 47 | 48 | // FilterSemver filters a set of tags by enforcing alpha >= beta >= stable. 49 | func FilterSemver(ch string, tags []string) (target *string) { 50 | v1, _ := semver.New("0.0.0") 51 | 52 | for _, tag := range tags { 53 | v2, err := semver.ParseTolerant(tag) 54 | if err != nil { 55 | continue 56 | } 57 | 58 | // In the case of a commit SHA that is all numbers, the semver will 59 | // successfully parse. This is a filter to ensure that we skip this 60 | // case. 61 | if v2.Major > 1 { 62 | continue 63 | } 64 | 65 | switch ch { 66 | case channel.StableChannel: 67 | if len(v2.Pre) > 0 { 68 | // Filter out all prereleases. 69 | continue 70 | } 71 | case channel.BetaChannel, channel.AlphaChannel: 72 | // Skip releases that could be X number of commits ahead of a stable 73 | // release (e.g. v0.1.0-X-gSHA, notice it is missing the alpha/beta). 74 | if len(v2.Pre) != 2 { 75 | break 76 | } 77 | 78 | // If the requested channel is beta, filter out all alphas. 79 | if ch == channel.BetaChannel && v2.Pre[0].String() == channel.AlphaChannel { 80 | continue 81 | } 82 | 83 | // All alpha and beta channels should never have a VersionStr, as that 84 | // would indicate that the version is of the form 85 | // major.minor.patch-pre.STRING (e.g. v0.1.0-alpha.0-abc) opposed to 86 | // major.minor.patch-pre.NUMBER (e.g. v0.1.0-alpha.0). The former means 87 | // this tag is in the "latest" channel. 88 | if v2.Pre[1].VersionStr != "" { 89 | continue 90 | } 91 | case channel.LatestChannel, channel.EdgeChannel: 92 | // Nothing to do. 93 | } 94 | 95 | if v1.LT(v2) { 96 | v1 = &v2 97 | } 98 | } 99 | 100 | // Ensure that we don't return the target if no tag was found. 101 | if v1.Major == 0 && v1.Minor == 0 && v1.Patch == 0 { 102 | return nil 103 | } 104 | 105 | // The "v" prefix is used in upstream tagging scheme. 106 | s := "v" + v1.String() 107 | target = &s 108 | 109 | return target 110 | } 111 | -------------------------------------------------------------------------------- /api/v1alpha1/zz_generated.deepcopy.go: -------------------------------------------------------------------------------- 1 | // +build !ignore_autogenerated 2 | 3 | // This Source Code Form is subject to the terms of the Mozilla Public 4 | // License, v. 2.0. If a copy of the MPL was not distributed with this 5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 | 7 | // Code generated by controller-gen. DO NOT EDIT. 8 | 9 | package v1alpha1 10 | 11 | import ( 12 | "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | runtime "k8s.io/apimachinery/pkg/runtime" 14 | ) 15 | 16 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 17 | func (in *Pool) DeepCopyInto(out *Pool) { 18 | *out = *in 19 | out.TypeMeta = in.TypeMeta 20 | in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) 21 | in.Spec.DeepCopyInto(&out.Spec) 22 | in.Status.DeepCopyInto(&out.Status) 23 | } 24 | 25 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pool. 26 | func (in *Pool) DeepCopy() *Pool { 27 | if in == nil { 28 | return nil 29 | } 30 | out := new(Pool) 31 | in.DeepCopyInto(out) 32 | return out 33 | } 34 | 35 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 36 | func (in *Pool) DeepCopyObject() runtime.Object { 37 | if c := in.DeepCopy(); c != nil { 38 | return c 39 | } 40 | return nil 41 | } 42 | 43 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 44 | func (in *PoolList) DeepCopyInto(out *PoolList) { 45 | *out = *in 46 | out.TypeMeta = in.TypeMeta 47 | in.ListMeta.DeepCopyInto(&out.ListMeta) 48 | if in.Items != nil { 49 | in, out := &in.Items, &out.Items 50 | *out = make([]Pool, len(*in)) 51 | for i := range *in { 52 | (*in)[i].DeepCopyInto(&(*out)[i]) 53 | } 54 | } 55 | } 56 | 57 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolList. 58 | func (in *PoolList) DeepCopy() *PoolList { 59 | if in == nil { 60 | return nil 61 | } 62 | out := new(PoolList) 63 | in.DeepCopyInto(out) 64 | return out 65 | } 66 | 67 | // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 68 | func (in *PoolList) DeepCopyObject() runtime.Object { 69 | if c := in.DeepCopy(); c != nil { 70 | return c 71 | } 72 | return nil 73 | } 74 | 75 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 76 | func (in *PoolSpec) DeepCopyInto(out *PoolSpec) { 77 | *out = *in 78 | if in.CheckInterval != nil { 79 | in, out := &in.CheckInterval, &out.CheckInterval 80 | *out = new(v1.Duration) 81 | **out = **in 82 | } 83 | } 84 | 85 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolSpec. 86 | func (in *PoolSpec) DeepCopy() *PoolSpec { 87 | if in == nil { 88 | return nil 89 | } 90 | out := new(PoolSpec) 91 | in.DeepCopyInto(out) 92 | return out 93 | } 94 | 95 | // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. 96 | func (in *PoolStatus) DeepCopyInto(out *PoolStatus) { 97 | *out = *in 98 | in.NextRun.DeepCopyInto(&out.NextRun) 99 | } 100 | 101 | // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PoolStatus. 102 | func (in *PoolStatus) DeepCopy() *PoolStatus { 103 | if in == nil { 104 | return nil 105 | } 106 | out := new(PoolStatus) 107 | in.DeepCopyInto(out) 108 | return out 109 | } 110 | -------------------------------------------------------------------------------- /hack/config/crd/upgrade.talos.dev_pools.yaml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: apiextensions.k8s.io/v1beta1 4 | kind: CustomResourceDefinition 5 | metadata: 6 | annotations: 7 | controller-gen.kubebuilder.io/version: v0.2.4 8 | creationTimestamp: null 9 | name: pools.upgrade.talos.dev 10 | spec: 11 | additionalPrinterColumns: 12 | - JSONPath: .spec.channel 13 | description: the pool's upgrade channel 14 | name: Channel 15 | type: string 16 | - JSONPath: .status.version 17 | description: the pool's target version 18 | name: Version 19 | type: string 20 | - JSONPath: .status.size 21 | description: the number of nodes in the pool 22 | name: Size 23 | type: integer 24 | - JSONPath: .spec.concurrency 25 | description: the pool's maximum number of concurrent upgrades 26 | name: Concurrency 27 | type: string 28 | - JSONPath: .status.nextRun 29 | description: when the next upgrade attempt will be made (UTC time standard) 30 | format: date-time 31 | name: Next Run 32 | type: string 33 | - JSONPath: .status.inProgress 34 | description: the nodes in the pool that are currently in progress of upgrading 35 | name: In Progress 36 | type: string 37 | group: upgrade.talos.dev 38 | names: 39 | kind: Pool 40 | listKind: PoolList 41 | plural: pools 42 | singular: pool 43 | scope: Cluster 44 | subresources: {} 45 | validation: 46 | openAPIV3Schema: 47 | description: Pool is the Schema for the pools API See https://book.kubebuilder.io/reference/markers/crd.html 48 | properties: 49 | apiVersion: 50 | description: 'APIVersion defines the versioned schema of this representation 51 | of an object. Servers should convert recognized schemas to the latest 52 | internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' 53 | type: string 54 | kind: 55 | description: 'Kind is a string value representing the REST resource this 56 | object represents. Servers may infer this from the endpoint the client 57 | submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' 58 | type: string 59 | metadata: 60 | type: object 61 | spec: 62 | description: PoolSpec defines the desired state of Pool 63 | properties: 64 | channel: 65 | type: string 66 | checkInterval: 67 | type: string 68 | concurrency: 69 | type: integer 70 | onFailure: 71 | type: string 72 | registry: 73 | type: string 74 | repository: 75 | type: string 76 | version: 77 | type: string 78 | type: object 79 | status: 80 | description: PoolStatus defines the observed state of Pool 81 | properties: 82 | inProgress: 83 | type: string 84 | nextRun: 85 | format: date-time 86 | type: string 87 | size: 88 | type: integer 89 | version: 90 | type: string 91 | type: object 92 | type: object 93 | version: v1alpha1 94 | versions: 95 | - name: v1alpha1 96 | served: true 97 | storage: true 98 | status: 99 | acceptedNames: 100 | kind: "" 101 | plural: "" 102 | conditions: [] 103 | storedVersions: [] 104 | -------------------------------------------------------------------------------- /.drone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | kind: pipeline 3 | type: kubernetes 4 | name: default 5 | 6 | steps: 7 | - name: setup-ci 8 | image: autonomy/build-container:latest 9 | commands: 10 | - git fetch --tags 11 | - install-ci-key 12 | - setup-buildx-amd64-arm64 13 | environment: 14 | SSH_KEY: 15 | from_secret: ssh_key 16 | resources: 17 | requests: 18 | cpu: 24000 19 | memory: 48GiB 20 | volumes: 21 | - name: outer-docker-socket 22 | path: /var/outer-run 23 | - name: docker-socket 24 | path: /var/run 25 | - name: buildx 26 | path: /root/.docker/buildx 27 | - name: ssh 28 | path: /root/.ssh 29 | 30 | - name: build-pull-request 31 | image: autonomy/build-container:latest 32 | pull: always 33 | commands: 34 | - make 35 | when: 36 | event: 37 | include: 38 | - pull_request 39 | volumes: 40 | - name: outer-docker-socket 41 | path: /var/outer-run 42 | - name: docker-socket 43 | path: /var/run 44 | - name: buildx 45 | path: /root/.docker/buildx 46 | - name: ssh 47 | path: /root/.ssh 48 | 49 | - name: build-and-publish 50 | image: autonomy/build-container:latest 51 | pull: always 52 | environment: 53 | DOCKER_USERNAME: 54 | from_secret: docker_username 55 | DOCKER_PASSWORD: 56 | from_secret: docker_password 57 | commands: 58 | - docker login --username "$${DOCKER_USERNAME}" --password "$${DOCKER_PASSWORD}" 59 | - make PUSH=true 60 | when: 61 | event: 62 | exclude: 63 | - pull_request 64 | volumes: 65 | - name: outer-docker-socket 66 | path: /var/outer-run 67 | - name: docker-socket 68 | path: /var/run 69 | - name: buildx 70 | path: /root/.docker/buildx 71 | - name: ssh 72 | path: /root/.ssh 73 | 74 | - name: build-yaml 75 | image: autonomy/build-container:latest 76 | pull: always 77 | commands: 78 | - make release 79 | when: 80 | event: 81 | - tag 82 | volumes: 83 | - name: outer-docker-socket 84 | path: /var/outer-run 85 | - name: docker-socket 86 | path: /var/run 87 | - name: buildx 88 | path: /root/.docker/buildx 89 | - name: ssh 90 | path: /root/.ssh 91 | 92 | - name: release 93 | image: plugins/github-release 94 | settings: 95 | api_key: 96 | from_secret: github_token 97 | checksum: 98 | - sha256 99 | - sha512 100 | draft: true 101 | files: 102 | - _out/* 103 | when: 104 | event: 105 | - tag 106 | 107 | services: 108 | - name: docker 109 | image: docker:19.03-dind 110 | entrypoint: 111 | - dockerd 112 | commands: 113 | - --dns=8.8.8.8 114 | - --dns=8.8.4.4 115 | - --mtu=1500 116 | - --log-level=error 117 | - --insecure-registry=http://registry.ci.svc:5000 118 | privileged: true 119 | volumes: 120 | - name: outer-docker-socket 121 | path: /var/outer-run 122 | - name: docker-socket 123 | path: /var/run 124 | - name: buildx 125 | path: /root/.docker/buildx 126 | - name: ssh 127 | path: /root/.ssh 128 | 129 | volumes: 130 | - name: outer-docker-socket 131 | host: 132 | path: /var/ci-docker 133 | - name: docker-socket 134 | temp: 135 | medium: memory 136 | - name: buildx 137 | temp: 138 | medium: memory 139 | - name: ssh 140 | temp: 141 | medium: memory 142 | 143 | --- 144 | kind: pipeline 145 | type: kubernetes 146 | name: notify 147 | 148 | clone: 149 | disable: true 150 | 151 | steps: 152 | - name: slack 153 | image: plugins/slack 154 | settings: 155 | webhook: 156 | from_secret: slack_webhook 157 | channel: proj-talos-maintainers 158 | when: 159 | status: 160 | - success 161 | - failure 162 | 163 | trigger: 164 | status: 165 | - success 166 | - failure 167 | 168 | depends_on: 169 | - default 170 | -------------------------------------------------------------------------------- /pkg/registry/registry.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package registry 6 | 7 | import ( 8 | "context" 9 | "encoding/json" 10 | "fmt" 11 | "log" 12 | "net/http" 13 | "net/url" 14 | 15 | "github.com/docker/distribution" 16 | "github.com/docker/distribution/manifest/schema2" 17 | "github.com/docker/distribution/reference" 18 | "github.com/docker/distribution/registry/client" 19 | "github.com/docker/distribution/registry/client/auth" 20 | "github.com/docker/distribution/registry/client/auth/challenge" 21 | "github.com/docker/distribution/registry/client/transport" 22 | digest "github.com/opencontainers/go-digest" 23 | ) 24 | 25 | type Repository struct { 26 | repository distribution.Repository 27 | } 28 | 29 | type CredentialStore struct { 30 | username string 31 | password string 32 | refreshTokens map[string]string 33 | } 34 | 35 | type TagFilter interface { 36 | Filter([]string) (string, error) 37 | } 38 | 39 | func (c *CredentialStore) Basic(*url.URL) (string, string) { 40 | return c.username, c.password 41 | } 42 | 43 | func (c *CredentialStore) RefreshToken(u *url.URL, service string) string { 44 | return c.refreshTokens[service] 45 | } 46 | 47 | func (c *CredentialStore) SetRefreshToken(u *url.URL, service string, token string) { 48 | if c.refreshTokens != nil { 49 | c.refreshTokens[service] = token 50 | } 51 | } 52 | 53 | // ping pings the provided endpoint to determine its required authorization challenges. 54 | // If a version header is provided, the versions will be returned. 55 | func Ping(manager challenge.Manager, endpoint, versionHeader string) ([]auth.APIVersion, error) { 56 | resp, err := http.Get(endpoint) 57 | if err != nil { 58 | return nil, err 59 | } 60 | defer resp.Body.Close() 61 | 62 | if err := manager.AddResponse(resp); err != nil { 63 | return nil, err 64 | } 65 | 66 | return auth.APIVersions(resp, versionHeader), err 67 | } 68 | 69 | func New(base, name string) (*Repository, error) { 70 | ref, err := reference.WithName(name) 71 | if err != nil { 72 | log.Fatal(err) 73 | } 74 | 75 | manager := challenge.NewSimpleManager() 76 | handler := auth.NewTokenHandler(http.DefaultTransport, &CredentialStore{}, ref.Name(), "pull") 77 | authorizer := auth.NewAuthorizer(manager, handler) 78 | transport := transport.NewTransport(http.DefaultTransport, authorizer) 79 | 80 | versions, err := Ping(manager, base+"/v2/", "Docker-Distribution-Api-Version") 81 | if err != nil { 82 | return nil, err 83 | } 84 | if len(versions) != 1 { 85 | return nil, fmt.Errorf("Unexpected version count: %d, expected 1", len(versions)) 86 | } 87 | if check := (auth.APIVersion{Type: "registry", Version: "2.0"}); versions[0] != check { 88 | return nil, fmt.Errorf("Unexpected api version: %q, expected %q", versions[0], check) 89 | } 90 | 91 | r, err := client.NewRepository(ref, base, transport) 92 | 93 | return &Repository{r}, nil 94 | } 95 | 96 | type Configuration struct { 97 | Config struct { 98 | Labels map[string]string `json:"labels"` 99 | } `json:"config"` 100 | } 101 | 102 | func (r *Repository) Configuration(dgst digest.Digest) (*Configuration, error) { 103 | blobs := r.repository.Blobs(context.Background()) 104 | 105 | b, err := blobs.Get(context.Background(), dgst) 106 | if err != nil { 107 | return nil, err 108 | } 109 | 110 | m := &Configuration{} 111 | if err := json.Unmarshal(b, m); err != nil { 112 | return nil, err 113 | } 114 | 115 | return m, nil 116 | } 117 | 118 | func (r *Repository) Manifest(tag string) (*distribution.Descriptor, error) { 119 | tags := r.repository.Tags(context.Background()) 120 | descriptor, err := tags.Get(context.Background(), tag) 121 | if err != nil { 122 | return nil, err 123 | } 124 | 125 | manifests, err := r.repository.Manifests(context.Background()) 126 | if err != nil { 127 | return nil, err 128 | } 129 | 130 | manifest, err := manifests.Get(context.Background(), descriptor.Digest, distribution.WithTagOption{Tag: tag}, distribution.WithManifestMediaTypesOption{MediaTypes: []string{schema2.MediaTypeManifest}}) 131 | if err != nil { 132 | return nil, err 133 | } 134 | 135 | if len(manifest.References()) == 0 { 136 | return nil, fmt.Errorf("expected at least 1 manifest") 137 | } 138 | 139 | return &manifest.References()[0], nil 140 | } 141 | 142 | func (r *Repository) Tags() ([]string, error) { 143 | tags := r.repository.Tags(context.Background()) 144 | all, err := tags.All(context.Background()) 145 | if err != nil { 146 | return nil, err 147 | } 148 | 149 | return all, nil 150 | } 151 | 152 | func (r *Repository) Tag(filter TagFilter) (string, error) { 153 | all, err := r.Tags() 154 | if err != nil { 155 | return "", err 156 | } 157 | 158 | return filter.Filter(all) 159 | } 160 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package main 6 | 7 | import ( 8 | "context" 9 | "flag" 10 | "log" 11 | "os" 12 | "time" 13 | 14 | poolv1alpha1 "github.com/talos-systems/talos-controller-manager/api/v1alpha1" 15 | "github.com/talos-systems/talos-controller-manager/pkg/controllers" 16 | "github.com/talos-systems/talos-controller-manager/pkg/upgrader" 17 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 | "k8s.io/apimachinery/pkg/runtime" 19 | "k8s.io/client-go/kubernetes" 20 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 21 | _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 22 | "k8s.io/client-go/rest" 23 | "k8s.io/client-go/tools/clientcmd" 24 | "k8s.io/client-go/tools/leaderelection" 25 | "k8s.io/client-go/tools/leaderelection/resourcelock" 26 | ctrl "sigs.k8s.io/controller-runtime" 27 | "sigs.k8s.io/controller-runtime/pkg/controller" 28 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 29 | "sigs.k8s.io/controller-runtime/pkg/manager" 30 | // +kubebuilder:scaffold:imports 31 | ) 32 | 33 | var ( 34 | scheme = runtime.NewScheme() 35 | setupLog = ctrl.Log.WithName("setup") 36 | ) 37 | 38 | func init() { 39 | _ = clientgoscheme.AddToScheme(scheme) 40 | 41 | _ = poolv1alpha1.AddToScheme(scheme) 42 | // +kubebuilder:scaffold:scheme 43 | } 44 | 45 | func run(mgr manager.Manager, leaseName, namespace string) (err error) { 46 | var config *rest.Config 47 | 48 | kubeconfig, ok := os.LookupEnv("KUBECONFIG") 49 | if ok { 50 | config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) 51 | if err != nil { 52 | return err 53 | } 54 | } else { 55 | config, err = rest.InClusterConfig() 56 | if err != nil { 57 | return err 58 | } 59 | } 60 | 61 | clientset, err := kubernetes.NewForConfig(config) 62 | if err != nil { 63 | log.Fatal(err) 64 | } 65 | 66 | id, err := os.Hostname() 67 | if err != nil { 68 | return err 69 | } 70 | 71 | lock := &resourcelock.LeaseLock{ 72 | LeaseMeta: metav1.ObjectMeta{ 73 | Name: leaseName, 74 | // TODO(andrewrynhard): Get the namespace from an env var. 75 | Namespace: namespace, 76 | }, 77 | Client: clientset.CoordinationV1(), 78 | LockConfig: resourcelock.ResourceLockConfig{ 79 | Identity: id, 80 | }, 81 | } 82 | 83 | leaderelection.RunOrDie(context.Background(), leaderelection.LeaderElectionConfig{ 84 | Lock: lock, 85 | // IMPORTANT: you MUST ensure that any code you have that 86 | // is protected by the lease must terminate **before** 87 | // you call cancel. Otherwise, you could have a background 88 | // loop still running and another process could 89 | // get elected before your background loop finished, violating 90 | // the stated goal of the lease. 91 | ReleaseOnCancel: true, 92 | LeaseDuration: 30 * time.Second, 93 | RenewDeadline: 15 * time.Second, 94 | RetryPeriod: 5 * time.Second, 95 | Callbacks: leaderelection.LeaderCallbacks{ 96 | OnStartedLeading: func(ctx context.Context) { 97 | setupLog.Info("starting manager") 98 | if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { 99 | setupLog.Error(err, "problem running manager") 100 | os.Exit(1) 101 | } 102 | }, 103 | OnStoppedLeading: func() { 104 | log.Println("lost leadership") 105 | os.Exit(0) 106 | }, 107 | OnNewLeader: func(identity string) { 108 | if identity == id { 109 | return 110 | } 111 | log.Printf("new leader elected: %s", identity) 112 | }, 113 | }, 114 | }) 115 | 116 | return nil 117 | } 118 | 119 | func main() { 120 | var metricsAddr string 121 | flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") 122 | flag.Parse() 123 | 124 | ctrl.SetLogger(zap.Logger(true)) 125 | 126 | mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ 127 | Scheme: scheme, 128 | MetricsBindAddress: metricsAddr, 129 | // We disable the builtin leader election in favor of using the leases API. 130 | LeaderElection: false, 131 | Port: 9443, 132 | }) 133 | if err != nil { 134 | setupLog.Error(err, "unable to start manager") 135 | os.Exit(1) 136 | } 137 | 138 | u, err := upgrader.NewV1Alpha1(mgr.GetClient()) 139 | if err != nil { 140 | setupLog.Error(err, "unable to create upgrader") 141 | os.Exit(1) 142 | } 143 | 144 | if err = (&controllers.PoolReconciler{ 145 | Client: mgr.GetClient(), 146 | Log: ctrl.Log.WithName("controllers").WithName("Pool"), 147 | Upgrader: u, 148 | }).SetupWithManager(mgr, controller.Options{MaxConcurrentReconciles: 10}); err != nil { 149 | setupLog.Error(err, "unable to create controller", "controller", "Pool") 150 | os.Exit(1) 151 | } 152 | // +kubebuilder:scaffold:builder 153 | 154 | setupLog.Info("starting manager") 155 | if err := run(mgr, "talos-controller-manager", "talos-system"); err != nil { 156 | setupLog.Error(err, "problem running manager") 157 | os.Exit(1) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /pkg/controllers/pool_controller.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package controllers 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "os" 11 | "strings" 12 | "time" 13 | 14 | "github.com/go-logr/logr" 15 | corev1 "k8s.io/api/core/v1" 16 | apierrors "k8s.io/apimachinery/pkg/api/errors" 17 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 | "k8s.io/apimachinery/pkg/labels" 19 | "k8s.io/apimachinery/pkg/selection" 20 | ctrl "sigs.k8s.io/controller-runtime" 21 | "sigs.k8s.io/controller-runtime/pkg/client" 22 | "sigs.k8s.io/controller-runtime/pkg/controller" 23 | 24 | poolv1alpha1 "github.com/talos-systems/talos-controller-manager/api/v1alpha1" 25 | "github.com/talos-systems/talos-controller-manager/pkg/channel" 26 | "github.com/talos-systems/talos-controller-manager/pkg/constants" 27 | "github.com/talos-systems/talos-controller-manager/pkg/upgrader" 28 | "github.com/talos-systems/talos-controller-manager/pkg/version" 29 | ) 30 | 31 | // PoolReconciler reconciles a Pool object 32 | type PoolReconciler struct { 33 | client.Client 34 | Log logr.Logger 35 | Upgrader upgrader.Upgrader 36 | } 37 | 38 | // +kubebuilder:rbac:groups=upgrade.talos.dev,resources=pools,verbs=get;list;watch;create;update;patch;delete 39 | // +kubebuilder:rbac:groups=upgrade.talos.dev,resources=pools/status,verbs=get;update;patch 40 | // +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;watch;create;update;patch;delete 41 | // +kubebuilder:rbac:groups="",resources=endpoints,verbs=get 42 | // +kubebuilder:rbac:groups="",resources=nodes,verbs=get;list;watch;update;patch 43 | 44 | func (r *PoolReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { 45 | ctx := context.Background() 46 | log := r.Log.WithValues("pool", req.Name) 47 | 48 | return r.reconcile(ctx, req, log) 49 | } 50 | 51 | func (r *PoolReconciler) SetupWithManager(mgr ctrl.Manager, options controller.Options) error { 52 | return ctrl.NewControllerManagedBy(mgr). 53 | WithOptions(options). 54 | For(&poolv1alpha1.Pool{}). 55 | Complete(r) 56 | } 57 | 58 | func (r *PoolReconciler) reconcile(ctx context.Context, req ctrl.Request, log logr.Logger) (ctrl.Result, error) { 59 | var pool poolv1alpha1.Pool 60 | 61 | if err := r.Get(ctx, req.NamespacedName, &pool); err != nil { 62 | if apierrors.IsNotFound(err) { 63 | return ctrl.Result{}, nil 64 | } 65 | 66 | log.Error(err, "unable to get pool") 67 | 68 | return ctrl.Result{}, err 69 | } 70 | 71 | // Update the version. 72 | 73 | v := pool.Spec.Version 74 | 75 | if v == "" { 76 | // TODO(andrewrynhard): Should these be configurable? 77 | channels := []channel.Channel{ 78 | channel.LatestChannel, 79 | channel.EdgeChannel, 80 | channel.AlphaChannel, 81 | channel.BetaChannel, 82 | channel.StableChannel, 83 | } 84 | 85 | cache := version.NewVersion(&version.V1Alpha1{}) 86 | 87 | go func() { 88 | if err := cache.Run(pool.Spec.Registry, pool.Spec.Repository, channels); err != nil { 89 | log.Error(err, "version cache failed") 90 | os.Exit(1) 91 | } 92 | }() 93 | 94 | if !cache.WaitForCacheSync() { 95 | return r.Result(ctx, req, false, log), fmt.Errorf("timeout waiting for version cache to sync") 96 | } 97 | 98 | var ok bool 99 | 100 | if v, ok = cache.Get(pool.Spec.Channel); !ok { 101 | return r.Result(ctx, req, false, log), fmt.Errorf("no version found for %q channel", pool.Spec.Channel) 102 | } 103 | 104 | log.Info("obtained version for pool", "version", v, "channel", pool.Spec.Channel) 105 | } 106 | 107 | if pool.Status.Version != v { 108 | pool.Status.Version = v 109 | 110 | if err := r.Update(context.TODO(), &pool); err != nil { 111 | return r.Result(ctx, req, false, log), err 112 | } 113 | } 114 | 115 | // Get all nodes that are part of the pool. 116 | 117 | label, err := labels.NewRequirement(constants.V1Alpha1PoolLabel, selection.Equals, []string{pool.Name}) 118 | if err != nil { 119 | return r.Result(ctx, req, false, log), err 120 | } 121 | 122 | opts := &client.ListOptions{ 123 | LabelSelector: labels.NewSelector().Add(*label), 124 | } 125 | 126 | var nodes corev1.NodeList 127 | 128 | if err := r.List(ctx, &nodes, opts); err != nil { 129 | return r.Result(ctx, req, false, log), err 130 | } 131 | 132 | // Update the size status. 133 | 134 | pool.Status.Size = len(nodes.Items) 135 | 136 | if err := r.Update(context.TODO(), &pool); err != nil { 137 | return r.Result(ctx, req, false, log), err 138 | } 139 | 140 | // Check if we should run an upgrade. 141 | 142 | if time.Until(pool.Status.NextRun.Time) > pool.Spec.CheckInterval.Duration { 143 | log.Info("rescheduling next run to checkInterval duration", "checkinterval", pool.Spec.CheckInterval.Duration) 144 | 145 | pool.Status.NextRun = metav1.NewTime(time.Now().UTC().Add(pool.Spec.CheckInterval.Duration)) 146 | 147 | if err := r.Update(context.TODO(), &pool); err != nil { 148 | return r.Result(ctx, req, false, log), err 149 | } 150 | 151 | return ctrl.Result{RequeueAfter: pool.Spec.CheckInterval.Duration}, nil 152 | } 153 | 154 | if pool.Status.NextRun.Time.After(time.Now().UTC()) { 155 | log.Info("skipping reconciliation, next run is in the future") 156 | return ctrl.Result{RequeueAfter: pool.Spec.CheckInterval.Duration}, nil 157 | } 158 | 159 | // Attempt to continue any existing upgrades. 160 | 161 | poolStatusInProgress := strings.Split(pool.Status.InProgress, ",") 162 | 163 | nodesInProgess := corev1.NodeList{} 164 | for _, node := range nodes.Items { 165 | for _, n := range poolStatusInProgress { 166 | if node.Name == n { 167 | nodesInProgess.Items = append(nodesInProgess.Items, node) 168 | } 169 | } 170 | } 171 | 172 | log.Info("upgrades in progress", "count", len(nodesInProgess.Items), "channel", pool.Spec.Channel) 173 | 174 | policy := upgrader.NewConcurrentPolicy(r.Upgrader, pool.Spec.Concurrency) 175 | 176 | if len(nodesInProgess.Items) > 0 { 177 | if err := policy.Run(req, nodesInProgess, v, true); err != nil { 178 | log.Error(err, "upgrade failed") 179 | 180 | return r.Result(ctx, req, true, log), err 181 | } 182 | } 183 | 184 | // Upgrade all nodes. 185 | 186 | if err := policy.Run(req, nodes, v, false); err != nil { 187 | log.Error(err, "upgrade failed") 188 | 189 | return r.Result(ctx, req, true, log), err 190 | } 191 | 192 | return r.Result(ctx, req, false, log), nil 193 | } 194 | 195 | func (r *PoolReconciler) Result(ctx context.Context, req ctrl.Request, fail bool, log logr.Logger) ctrl.Result { 196 | var pool poolv1alpha1.Pool 197 | 198 | if err := r.Get(ctx, req.NamespacedName, &pool); err != nil { 199 | if apierrors.IsNotFound(err) { 200 | return ctrl.Result{} 201 | } 202 | 203 | log.Error(err, "unable to get pool") 204 | 205 | return ctrl.Result{} 206 | } 207 | 208 | next := metav1.NewTime(time.Now().UTC().Add(pool.Spec.CheckInterval.Duration)) 209 | 210 | defer func() { 211 | if err := r.Update(ctx, &pool); err != nil { 212 | log.Error(err, "failed to update pool") 213 | } 214 | }() 215 | 216 | if fail { 217 | switch pool.Spec.FailurePolicy { 218 | case "Pause": 219 | pool.Status.NextRun = metav1.Time{} 220 | 221 | log.Info("pausing upgrades") 222 | 223 | return ctrl.Result{Requeue: false} 224 | case "Retry": 225 | // Nothing to do. 226 | } 227 | } 228 | 229 | pool.Status.NextRun = next 230 | 231 | log.Info("requeuing upgrade", "when", next.Time) 232 | 233 | return ctrl.Result{RequeueAfter: pool.Spec.CheckInterval.Duration} 234 | } 235 | -------------------------------------------------------------------------------- /pkg/upgrader/upgrader_v1alpha1.go: -------------------------------------------------------------------------------- 1 | // This Source Code Form is subject to the terms of the Mozilla Public 2 | // License, v. 2.0. If a copy of the MPL was not distributed with this 3 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | package upgrader 6 | 7 | import ( 8 | "bufio" 9 | "bytes" 10 | "context" 11 | "fmt" 12 | "io" 13 | "net" 14 | "os" 15 | "strings" 16 | "time" 17 | 18 | "github.com/go-logr/logr" 19 | "github.com/pkg/errors" 20 | poolv1alpha1 "github.com/talos-systems/talos-controller-manager/api/v1alpha1" 21 | 22 | "github.com/talos-systems/talos/api/common" 23 | machineapi "github.com/talos-systems/talos/api/machine" 24 | "github.com/talos-systems/talos/cmd/osctl/pkg/client" 25 | talosconstants "github.com/talos-systems/talos/pkg/constants" 26 | "github.com/talos-systems/talos/pkg/grpc/tls" 27 | taloskubernetes "github.com/talos-systems/talos/pkg/kubernetes" 28 | "github.com/talos-systems/talos/pkg/retry" 29 | "google.golang.org/grpc/codes" 30 | "google.golang.org/grpc/status" 31 | corev1 "k8s.io/api/core/v1" 32 | apierrors "k8s.io/apimachinery/pkg/api/errors" 33 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 | "k8s.io/client-go/rest" 35 | restclient "k8s.io/client-go/rest" 36 | ctrl "sigs.k8s.io/controller-runtime" 37 | ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" 38 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 39 | ) 40 | 41 | type V1Alpha1 struct { 42 | log logr.Logger 43 | ctrlclient ctrlclient.Client 44 | talosclient *client.Client 45 | kubeclient *taloskubernetes.Client 46 | } 47 | 48 | func NewV1Alpha1(ctrlclient ctrlclient.Client) (v *V1Alpha1, err error) { 49 | var config *restclient.Config 50 | 51 | config, err = rest.InClusterConfig() 52 | if err != nil { 53 | return nil, err 54 | } 55 | 56 | kubeclient, err := taloskubernetes.NewForConfig(config) 57 | if err != nil { 58 | return nil, fmt.Errorf("failed to create client: %w", err) 59 | } 60 | 61 | var endpoints []string 62 | 63 | endpoints, err = kubeclient.MasterIPs() 64 | if err != nil { 65 | return nil, err 66 | } 67 | 68 | var ( 69 | token string 70 | ok bool 71 | ) 72 | 73 | if token, ok = os.LookupEnv("TALOS_TOKEN"); !ok { 74 | return nil, errors.New("TALOS_TOKEN env var is required") 75 | } 76 | 77 | hostname, err := os.Hostname() 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | certificateProvider, err := tls.NewRemoteRenewingFileCertificateProvider( 83 | token, 84 | endpoints, 85 | talosconstants.TrustdPort, 86 | []string{hostname}, 87 | []net.IP{}, 88 | ) 89 | if err != nil { 90 | return nil, err 91 | } 92 | 93 | ca, err := certificateProvider.GetCA() 94 | if err != nil { 95 | return nil, fmt.Errorf("failed to get root CA: %w", err) 96 | } 97 | 98 | creds, err := tls.New( 99 | tls.WithClientAuthType(tls.Mutual), 100 | tls.WithCACertPEM(ca), 101 | tls.WithClientCertificateProvider(certificateProvider), 102 | ) 103 | 104 | talosclient, err := client.NewClient(creds, endpoints, talosconstants.ApidPort) 105 | if err != nil { 106 | return nil, fmt.Errorf("error constructing client: %w", err) 107 | } 108 | 109 | v = &V1Alpha1{ 110 | log: ctrl.Log.WithName("v1alpha1").WithName("Upgrader"), 111 | ctrlclient: ctrlclient, 112 | talosclient: talosclient, 113 | kubeclient: kubeclient, 114 | } 115 | 116 | return v, nil 117 | } 118 | 119 | func (v1alpha1 V1Alpha1) Upgrade(req reconcile.Request, node corev1.Node, tag string, inProgess bool) (err error) { 120 | var pool poolv1alpha1.Pool 121 | if err := v1alpha1.ctrlclient.Get(context.Background(), req.NamespacedName, &pool); err != nil { 122 | if apierrors.IsNotFound(err) { 123 | return nil 124 | } 125 | 126 | return err 127 | } 128 | 129 | if pool.Spec.Repository == "" { 130 | return errors.New("a repository is required") 131 | } 132 | 133 | // TODO(andrewrynhard): This should be passed in. 134 | image := fmt.Sprintf("docker.io/%s:%s", pool.Spec.Repository, tag) 135 | 136 | // TODO(andrewrynhard): Ensure that we have found the internal address. 137 | var target string 138 | for _, addr := range node.Status.Addresses { 139 | if addr.Type == corev1.NodeInternalIP { 140 | target = addr.Address 141 | } 142 | } 143 | 144 | // TODO(andrewrynhard): Request upgrade with context timeout. 145 | ctx := client.WithNodes(context.Background(), target) 146 | 147 | version, err := v1alpha1.getVersion(ctx) 148 | if err != nil { 149 | return err 150 | } 151 | 152 | // TODO(andrewrynhard): Use semantic versioning to figure out if the 153 | // the node is on an older version. 154 | upToDate := version.Tag == tag 155 | 156 | switch { 157 | case upToDate && inProgess: 158 | // This means that the current operator has become the leader, but 159 | // another operator initiated the upgrade and failed to remove the 160 | // in progress status for some reason. So we skip making an upgrade 161 | // request and try to pick up where the upgrade left off. 162 | fallthrough 163 | case !upToDate && inProgess: 164 | // See above case. 165 | case upToDate && !inProgess: 166 | v1alpha1.log.Info("node is up to date", "node", node.Name, "version", version.Tag) 167 | return nil 168 | case !upToDate && !inProgess: 169 | v1alpha1.log.Info("upgrading node", "node", node.Name, "current version", version.Tag, "target version", tag, "installer", image) 170 | 171 | // TODO(andrewrynhard): Remove this. 172 | time.Sleep(5 * time.Second) 173 | 174 | v1alpha1.log.Info("sending upgrade request", "node", node.Name) 175 | 176 | _, err = v1alpha1.talosclient.Upgrade(ctx, image) 177 | if err != nil { 178 | return fmt.Errorf("upgrade request failed: %w", err) 179 | } 180 | 181 | if err = v1alpha1.setInProgress(req, node.Name); err != nil { 182 | return err 183 | } 184 | } 185 | 186 | logCtx, logCancel := context.WithCancel(ctx) 187 | 188 | defer logCancel() 189 | 190 | // TODO(andrewrynhard): Reconnect and stream logs on error. 191 | // nolint: errcheck 192 | go v1alpha1.streamLogs(logCtx, node) 193 | 194 | if err = v1alpha1.verifyUpgrade(ctx, tag, node); err != nil { 195 | return err 196 | } 197 | 198 | if err = v1alpha1.cleanup(node); err != nil { 199 | return err 200 | } 201 | 202 | if err = v1alpha1.removeInProgress(req, node.Name); err != nil { 203 | v1alpha1.log.Error(err, "failed to remove node from pool in progress status") 204 | } 205 | 206 | v1alpha1.log.Info("upgrade successful", "node", node.Name, "version", tag) 207 | 208 | return nil 209 | } 210 | 211 | func (v1alpha1 *V1Alpha1) setInProgress(req reconcile.Request, name string) error { 212 | var pool poolv1alpha1.Pool 213 | if err := v1alpha1.ctrlclient.Get(context.Background(), req.NamespacedName, &pool); err != nil { 214 | if apierrors.IsNotFound(err) { 215 | return nil 216 | } 217 | 218 | return err 219 | } 220 | 221 | f := func(c rune) bool { 222 | return c == ',' 223 | } 224 | 225 | nodes := strings.FieldsFunc(pool.Status.InProgress, f) 226 | nodes = append(nodes, name) 227 | pool.Status.InProgress = strings.Join(nodes, ",") 228 | if err := v1alpha1.ctrlclient.Update(context.TODO(), &pool); err != nil { 229 | return err 230 | } 231 | 232 | return nil 233 | } 234 | 235 | func (v1alpha1 *V1Alpha1) removeInProgress(req reconcile.Request, name string) error { 236 | var pool poolv1alpha1.Pool 237 | if err := v1alpha1.ctrlclient.Get(context.Background(), req.NamespacedName, &pool); err != nil { 238 | if apierrors.IsNotFound(err) { 239 | return nil 240 | } 241 | 242 | return err 243 | } 244 | 245 | nodes := strings.Split(pool.Status.InProgress, ",") 246 | tmp := []string{} 247 | for _, node := range nodes { 248 | if node == name { 249 | continue 250 | } 251 | 252 | tmp = append(tmp, node) 253 | } 254 | pool.Status.InProgress = strings.Join(tmp, ",") 255 | if err := v1alpha1.ctrlclient.Update(context.TODO(), &pool); err != nil { 256 | return err 257 | } 258 | 259 | return nil 260 | } 261 | 262 | func (v1alpha1 *V1Alpha1) waitForHealthy(node corev1.Node) (err error) { 263 | wait := func() error { 264 | err = retry.Constant(15*time.Minute, retry.WithUnits(3*time.Second), retry.WithJitter(500*time.Millisecond)).Retry(func() error { 265 | n, err := v1alpha1.kubeclient.CoreV1().Nodes().Get(node.Name, metav1.GetOptions{}) 266 | if err != nil { 267 | return retry.ExpectedError(err) 268 | } 269 | 270 | for _, condition := range n.Status.Conditions { 271 | if condition.Type == corev1.NodeReady { 272 | if condition.Status == corev1.ConditionFalse { 273 | return retry.ExpectedError(errors.New("node not ready")) 274 | } 275 | } 276 | } 277 | 278 | return nil 279 | }) 280 | 281 | return err 282 | } 283 | 284 | for i := 0; i < 3; i++ { 285 | if err = wait(); err != nil { 286 | return err 287 | } 288 | 289 | time.Sleep(10 * time.Second) 290 | } 291 | 292 | return nil 293 | } 294 | 295 | func (v1alpha1 *V1Alpha1) getVersion(ctx context.Context) (version *machineapi.VersionInfo, err error) { 296 | err = retry.Constant(15*time.Minute, retry.WithUnits(3*time.Second), retry.WithJitter(500*time.Millisecond)).Retry(func() error { 297 | var versions *machineapi.VersionResponse 298 | 299 | versions, err = v1alpha1.talosclient.Version(ctx) 300 | if err != nil { 301 | return retry.ExpectedError(err) 302 | } 303 | 304 | version = versions.Messages[0].Version 305 | 306 | return nil 307 | }) 308 | 309 | if err != nil { 310 | return nil, err 311 | } 312 | 313 | return version, nil 314 | } 315 | 316 | func (v1alpha1 *V1Alpha1) streamLogs(ctx context.Context, node corev1.Node) error { 317 | stream, err := v1alpha1.talosclient.Logs(ctx, "system", common.ContainerDriver_CONTAINERD, "machined", true, 0) 318 | if err != nil { 319 | v1alpha1.log.Error(err, "error fetching logs") 320 | } 321 | 322 | for { 323 | var data *common.Data 324 | data, err = stream.Recv() 325 | if err != nil { 326 | if err == io.EOF || status.Code(err) == codes.Canceled { 327 | return nil 328 | } 329 | 330 | v1alpha1.log.Error(err, "error streaming logs") 331 | 332 | return err 333 | } 334 | 335 | r := bytes.NewReader(data.Bytes) 336 | 337 | scanner := bufio.NewScanner(r) 338 | for scanner.Scan() { 339 | v1alpha1.log.Info("upgrade log", "node", node.Name, "log", scanner.Text()) 340 | } 341 | } 342 | } 343 | 344 | func (v1alpha1 *V1Alpha1) cleanup(node corev1.Node) (err error) { 345 | if err = v1alpha1.kubeclient.Uncordon(node.Name); err != nil { 346 | v1alpha1.log.Error(err, "failed to undordon node", "node", node.Name) 347 | } 348 | 349 | v1alpha1.log.Info("node uncordoned", "node", node.Name) 350 | 351 | return nil 352 | } 353 | 354 | func (v1alpha1 *V1Alpha1) verifyUpgrade(ctx context.Context, tag string, node corev1.Node) error { 355 | ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) 356 | defer cancel() 357 | for { 358 | version, err := v1alpha1.getVersion(ctx) 359 | if err != nil { 360 | return err 361 | } 362 | 363 | if version.Tag != tag { 364 | time.Sleep(10 * time.Second) 365 | continue 366 | } 367 | 368 | if err = v1alpha1.waitForHealthy(node); err != nil { 369 | return fmt.Errorf("node is not healthy: %w", err) 370 | } 371 | 372 | v1alpha1.log.Info("node is healthy", "node", node.Name) 373 | 374 | return nil 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= 4 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 5 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 6 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= 8 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 9 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 10 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 11 | code.cloudfoundry.org/bytefmt v0.0.0-20180906201452-2aa6f33b730c/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= 12 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 13 | github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= 14 | github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= 15 | github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= 16 | github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 17 | github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= 18 | github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= 19 | github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 20 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 21 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 22 | github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= 23 | github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= 24 | github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= 25 | github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= 26 | github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= 27 | github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 28 | github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 29 | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= 30 | github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 31 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= 32 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 33 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 34 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 35 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 36 | github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= 37 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 38 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 39 | github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 40 | github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= 41 | github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= 42 | github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= 43 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 44 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 45 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 46 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 47 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= 48 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 49 | github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 50 | github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= 51 | github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 52 | github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= 53 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 54 | github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= 55 | github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= 56 | github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= 57 | github.com/cilium/ebpf v0.0.0-20191113100448-d9fb101ca1fb/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= 58 | github.com/cjbassi/drawille-go v0.0.0-20190126131713-27dc511fe6fd/go.mod h1:vjcQJUZJYD3MeVGhtZXSMnCHfUNZxsyYzJt90eCYxK4= 59 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 60 | github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= 61 | github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= 62 | github.com/containerd/cgroups v0.0.0-20191125132625-80b32e3c75c9/go.mod h1:FwbKQCduYoQfIgPclXEWCx5nXWYmnAV7+syVQrs+Z/w= 63 | github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= 64 | github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 65 | github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F0UxetA= 66 | github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 67 | github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= 68 | github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= 69 | github.com/containerd/cri v1.11.1/go.mod h1:DavH5Qa8+6jOmeOMO3dhWoqksucZDe06LfuhBz/xPZs= 70 | github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= 71 | github.com/containerd/fifo v0.0.0-20190816180239-bda0ff6ed73c/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= 72 | github.com/containerd/go-cni v0.0.0-20191121212822-60d125212faf h1:eUNDEEbhwN0Tolk2blxdXaVItt8sd0aLTDSgcyqyTnE= 73 | github.com/containerd/go-cni v0.0.0-20191121212822-60d125212faf/go.mod h1:0mg8r6FCdbxvLDqCXwAx2rO+KA37QICjKL8+wHOG5OE= 74 | github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= 75 | github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= 76 | github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= 77 | github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= 78 | github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= 79 | github.com/containernetworking/cni v0.7.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= 80 | github.com/containernetworking/cni v0.7.1 h1:fE3r16wpSEyaqY4Z4oFrLMmIGfBYIKpPrHK31EJ9FzE= 81 | github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= 82 | github.com/containernetworking/cni v0.7.2-0.20190807151350-8c6c47d1c7fc h1:zUNdrf9w09mWodVhZ9hX4Yk4Uu84n/OgdfPattAwwt8= 83 | github.com/containernetworking/cni v0.7.2-0.20190807151350-8c6c47d1c7fc/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= 84 | github.com/containernetworking/plugins v0.8.2/go.mod h1:TxALKWZpWL79BC3GOYKJzzXr7U8R23PdhwaLp6F3adc= 85 | github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 86 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 87 | github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 88 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 89 | github.com/coreos/go-iptables v0.4.2/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= 90 | github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= 91 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 92 | github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 93 | github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 94 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 95 | github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 96 | github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 97 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 98 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 99 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 100 | github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= 101 | github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= 102 | github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= 103 | github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= 104 | github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 105 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 106 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 107 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 108 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 109 | github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= 110 | github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 111 | github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 112 | github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 113 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 114 | github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= 115 | github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= 116 | github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= 117 | github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 118 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 119 | github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= 120 | github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= 121 | github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= 122 | github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= 123 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 124 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 125 | github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= 126 | github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 127 | github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 128 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 129 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 130 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 131 | github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 132 | github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= 133 | github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 134 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 135 | github.com/firecracker-microvm/firecracker-go-sdk v0.19.0/go.mod h1:kW0gxvPpPvMukUxxTO9DrpSlScrtrTDGY3VgjAj/Qwc= 136 | github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= 137 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 138 | github.com/fullsailor/pkcs7 v0.0.0-20180613152042-8306686428a5/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= 139 | github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 140 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 141 | github.com/gizak/termui/v3 v3.0.0/go.mod h1:uinu2dMdtMI+FTIdEFUJQT5y+KShnhQRshvPblXq3lY= 142 | github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= 143 | github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= 144 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 145 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 146 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 147 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 148 | github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= 149 | github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= 150 | github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= 151 | github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= 152 | github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= 153 | github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= 154 | github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= 155 | github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= 156 | github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= 157 | github.com/go-openapi/errors v0.17.1/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= 158 | github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= 159 | github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= 160 | github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= 161 | github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= 162 | github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= 163 | github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= 164 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 165 | github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= 166 | github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= 167 | github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= 168 | github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= 169 | github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= 170 | github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= 171 | github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= 172 | github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= 173 | github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= 174 | github.com/go-openapi/runtime v0.17.1/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q= 175 | github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= 176 | github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= 177 | github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= 178 | github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= 179 | github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= 180 | github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= 181 | github.com/go-openapi/strfmt v0.17.1/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= 182 | github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= 183 | github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= 184 | github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= 185 | github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= 186 | github.com/go-openapi/swag v0.17.1/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= 187 | github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= 188 | github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 189 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 190 | github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= 191 | github.com/go-openapi/validate v0.17.1/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= 192 | github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= 193 | github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= 194 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 195 | github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= 196 | github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= 197 | github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= 198 | github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 199 | github.com/gogo/googleapis v1.3.0/go.mod h1:d+q1s/xVJxZGKWwC/6UfPIF33J+G1Tq4GYv9Y+Tg/EU= 200 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 201 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 202 | github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 203 | github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 204 | github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= 205 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 206 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 207 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 208 | github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 209 | github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 210 | github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE= 211 | github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 212 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 213 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 214 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 215 | github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 216 | github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 217 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 218 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 219 | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= 220 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 221 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 222 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 223 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 224 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 225 | github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= 226 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 227 | github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= 228 | github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= 229 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 230 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 231 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 232 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 233 | github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 234 | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= 235 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 236 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 237 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 238 | github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= 239 | github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= 240 | github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= 241 | github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= 242 | github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= 243 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 244 | github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 245 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 246 | github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 247 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 248 | github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 249 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 250 | github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= 251 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 252 | github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= 253 | github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 254 | github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 255 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 256 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 257 | github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 258 | github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= 259 | github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= 260 | github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= 261 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 262 | github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= 263 | github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 264 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 265 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 266 | github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= 267 | github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 268 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 269 | github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= 270 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 271 | github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= 272 | github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 273 | github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 274 | github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= 275 | github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= 276 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 277 | github.com/insomniacslk/dhcp v0.0.0-20190814082028-393ae75a101b/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw= 278 | github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= 279 | github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 280 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 281 | github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= 282 | github.com/jsimonetti/rtnetlink v0.0.0-20191223084007-1b9462860ac0/go.mod h1:jA+FtkQ4/SGYz0Nix1so2WXNe/KnqVVJEDGukExrlM8= 283 | github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 284 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 285 | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 286 | github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= 287 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 288 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 289 | github.com/juju/errors v0.0.0-20180806074554-22422dad46e1/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= 290 | github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= 291 | github.com/juju/testing v0.0.0-20190613124551-e81189438503/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= 292 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 293 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 294 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 295 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 296 | github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 297 | github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= 298 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 299 | github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= 300 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 301 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 302 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 303 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 304 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 305 | github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= 306 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 307 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 308 | github.com/kubernetes-sigs/bootkube v0.14.1-0.20190731222813-f0fc1bdb404d/go.mod h1:S1oz0QOCDDrAYhj24SBOIdFC6Pj/idkUxRalnBPr6ts= 309 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 310 | github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 311 | github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 312 | github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 313 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 314 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 315 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 316 | github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 317 | github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 318 | github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 319 | github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= 320 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 321 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 322 | github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= 323 | github.com/mdlayher/genetlink v0.0.0-20190313224034-60417448a851/go.mod h1:EsbsAEUEs15qC1cosAwxgCWV0Qhd8TmkxnA9Kw1Vhl4= 324 | github.com/mdlayher/netlink v0.0.0-20190313131330-258ea9dff42c/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= 325 | github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= 326 | github.com/mdlayher/netlink v0.0.0-20191008140946-2a17fd90af51/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= 327 | github.com/mdlayher/netlink v0.0.0-20191009155606-de872b0d824b/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= 328 | github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= 329 | github.com/mdlayher/raw v0.0.0-20190606144222-a54781e5f38f/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= 330 | github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 331 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 332 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 333 | github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= 334 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 335 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 336 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 337 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 338 | github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 339 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 340 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 341 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 342 | github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 343 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 344 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 345 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 346 | github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= 347 | github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= 348 | github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 349 | github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 350 | github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 351 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 352 | github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 353 | github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= 354 | github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 355 | github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= 356 | github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 357 | github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 358 | github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 359 | github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 360 | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 361 | github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= 362 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 363 | github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= 364 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 365 | github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 366 | github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= 367 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 368 | github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= 369 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 370 | github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= 371 | github.com/opencontainers/runc v1.0.0-rc8/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= 372 | github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= 373 | github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= 374 | github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= 375 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 376 | github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= 377 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 378 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 379 | github.com/pin/tftp v2.1.0+incompatible/go.mod h1:xVpZOMCXTy+A5QMjEVN0Glwa1sUvaJhFXbr/aAxuxGY= 380 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 381 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 382 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 383 | github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 384 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 385 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 386 | github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= 387 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 388 | github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= 389 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 390 | github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= 391 | github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= 392 | github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= 393 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 394 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 395 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= 396 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 397 | github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 398 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 399 | github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= 400 | github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= 401 | github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= 402 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 403 | github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 404 | github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 405 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 406 | github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= 407 | github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= 408 | github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= 409 | github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= 410 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 411 | github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= 412 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 413 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 414 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 415 | github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 416 | github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= 417 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 418 | github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= 419 | github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= 420 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 421 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 422 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 423 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 424 | github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 425 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 426 | github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c/go.mod h1:eMyUVp6f/5jnzM+3zahzl7q6UXLbgSc3MKg/+ow9QW0= 427 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 428 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 429 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 430 | github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 431 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 432 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 433 | github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 434 | github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 435 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 436 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 437 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 438 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 439 | github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 440 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 441 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 442 | github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= 443 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 444 | github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 445 | github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 446 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 447 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 448 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 449 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 450 | github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= 451 | github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= 452 | github.com/talos-systems/grpc-proxy v0.2.0 h1:DN75bLfaW4xfhq0r0mwFRnfGhSB+HPhK1LNzuMEs9Pw= 453 | github.com/talos-systems/grpc-proxy v0.2.0/go.mod h1:sm97Vc/z2cok3pu6ruNeszQej4KDxFrDgfWs4C1mtC4= 454 | github.com/talos-systems/talos v0.4.0-alpha.2.0.20200122012516-e7749d2e8fce h1:FWOtOYESw/f2T//ve3SHatwrfksIpBagG0shyQeSAlE= 455 | github.com/talos-systems/talos v0.4.0-alpha.2.0.20200122012516-e7749d2e8fce/go.mod h1:m+kfCl0F4C2XUibjPv/wd3dPev7E2k5R6C/JP0DPldI= 456 | github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 457 | github.com/u-root/u-root v6.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= 458 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 459 | github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 460 | github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 461 | github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 462 | github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= 463 | github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= 464 | github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= 465 | github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk= 466 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= 467 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= 468 | github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= 469 | github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 470 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 471 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 472 | go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 473 | go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= 474 | go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= 475 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 476 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 477 | go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 478 | go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= 479 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 480 | go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= 481 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 482 | go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 483 | go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= 484 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 485 | go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 486 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 487 | go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= 488 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 489 | golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8= 490 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 491 | golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 492 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 493 | golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 494 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 495 | golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 496 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 497 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 498 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 499 | golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= 500 | golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 501 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 502 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 503 | golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 504 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 505 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 506 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 507 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 508 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 509 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 510 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 511 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 512 | golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 513 | golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 514 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 515 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 516 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 517 | golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 518 | golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 519 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 520 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 521 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 522 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 523 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 524 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 525 | golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 526 | golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 527 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 528 | golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 529 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 530 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 531 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 532 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 533 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 534 | golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 535 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 536 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 537 | golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 538 | golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 539 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= 540 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 541 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 542 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 543 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= 544 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 545 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 546 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 547 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 548 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 549 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 550 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= 551 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 552 | golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 553 | golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 554 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 555 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 556 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 557 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 558 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 559 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 560 | golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 561 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 562 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 563 | golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 564 | golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 565 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 566 | golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 567 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 568 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 569 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 570 | golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 571 | golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 572 | golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 573 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 574 | golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 575 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 576 | golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 577 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 578 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 579 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 580 | golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 581 | golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 582 | golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 583 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50 h1:YvQ10rzcqWXLlJZ3XCUoO25savxmscf4+SC+ZqiCHhA= 584 | golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 585 | golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 586 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 587 | golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 588 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 589 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 590 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 591 | golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 592 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 593 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 594 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= 595 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 596 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 597 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 598 | golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 599 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 600 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 601 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 602 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 603 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 604 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 605 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 606 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 607 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 608 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 609 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 610 | golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 611 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 612 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 613 | golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 614 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 615 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= 616 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 617 | gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= 618 | gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= 619 | gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= 620 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 621 | gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= 622 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 623 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 624 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 625 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 626 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 627 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 628 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 629 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 630 | google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= 631 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 632 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 633 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 634 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 635 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 636 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg= 637 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 638 | google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= 639 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 640 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= 641 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 642 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 643 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 644 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 645 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 646 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 647 | google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= 648 | google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 649 | google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= 650 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 651 | google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= 652 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 653 | gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 654 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 655 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 656 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 657 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 658 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 659 | gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 660 | gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 661 | gopkg.in/freddierice/go-losetup.v1 v1.0.0-20170407175016-fc9adea44124/go.mod h1:6LXpUYtVsrx91XiupFRJ8jVKOqLZf5PrbEVSGHta/84= 662 | gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= 663 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 664 | gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= 665 | gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 666 | gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= 667 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 668 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 669 | gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 670 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 671 | gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 672 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 673 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 674 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 675 | gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 676 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 677 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 678 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 679 | gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= 680 | gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 681 | gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= 682 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 683 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 684 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 685 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 686 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 687 | k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= 688 | k8s.io/api v0.0.0-20191108065827-59e77acf588f h1:ZTXCVdYGBbAblNUJ5B19ztoy6WHMNrPerxQJF9agLpY= 689 | k8s.io/api v0.0.0-20191108065827-59e77acf588f/go.mod h1:uQDmBYHoPSuhbg8FGTRzrOdaNqLiws/LAtBrHv0kN5U= 690 | k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM= 691 | k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= 692 | k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY= 693 | k8s.io/apiextensions-apiserver v0.0.0-20191108071732-08c66a398f44 h1:KtHV1Q8mtnt1I3Qdde1HONJhygwsfckx1rLM0tT/flM= 694 | k8s.io/apiextensions-apiserver v0.0.0-20191108071732-08c66a398f44/go.mod h1:5d+EQSecqCsBQWVcepW1U6yWhRr3g1wEG4Cqrs1Tn8Y= 695 | k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= 696 | k8s.io/apimachinery v0.0.0-20191108065633-c18f71bf2947 h1:f3H3Rf7KD9fjmmbIMwxBye3ctEuXnbskaX/l1xy+68E= 697 | k8s.io/apimachinery v0.0.0-20191108065633-c18f71bf2947/go.mod h1:nEP/6rwhzfljWYGVS6pfyES3ipZTR19vzMnSM+ur3ho= 698 | k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo= 699 | k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= 700 | k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg= 701 | k8s.io/apiserver v0.0.0-20191108070917-918776919ce1/go.mod h1:Q243OTKWzXssSV7TuvAcaHVdS20h/iQ38SnXWxym0No= 702 | k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk= 703 | k8s.io/client-go v0.0.0-20191108070106-f8f007fd456c h1:TaCF427jtkNsXDzSNXOFFox1DePy6WX9Nf8E1vriHys= 704 | k8s.io/client-go v0.0.0-20191108070106-f8f007fd456c/go.mod h1:D6hkzmLWI59QLvDVt8tlD5J2X1YDjcattS6vw8lP1hc= 705 | k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg= 706 | k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= 707 | k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= 708 | k8s.io/code-generator v0.0.0-20191108065441-3c1097069dc3/go.mod h1:OJTI2RPXj6kq4bfFqT1JrTEC1S4toTWinGOm1O8jUuY= 709 | k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA= 710 | k8s.io/component-base v0.0.0-20191108070619-4b9966ca0181/go.mod h1:OnLnQI0ti1wNBL+pCumQcG9Plt1S6L+lOXsQwQJ+m9g= 711 | k8s.io/cri-api v0.0.0-20191121183020-775aa3c1cf73/go.mod h1:BzAkbBHHp81d+aXzbiIcUbilLkbXa40B8mUHOk6EX3s= 712 | k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 713 | k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= 714 | k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 715 | k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= 716 | k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 717 | k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= 718 | k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 719 | k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= 720 | k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= 721 | k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= 722 | k8s.io/kubelet v0.17.0/go.mod h1:e/JBCxucKuEV6JO6zYW+e72ib9eMsGO2Fah3iT5tiiI= 723 | k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= 724 | k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 725 | k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d h1:1P0iBJsBzxRmR+dIFnM+Iu4aLxnoa7lBqozW/0uHbT8= 726 | k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 727 | k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= 728 | k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= 729 | modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= 730 | modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= 731 | modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= 732 | modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= 733 | modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= 734 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 735 | sigs.k8s.io/controller-runtime v0.3.1-0.20191105233659-81842d0e78f7 h1:0MQ66X77oJ3B2CnBAQ/wEfq7t8qetVEL62ZSDK6z//o= 736 | sigs.k8s.io/controller-runtime v0.3.1-0.20191105233659-81842d0e78f7/go.mod h1:DNfMNM85UKERNQ7WRzae+12gU99u6CMBHND4nCyLisM= 737 | sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 738 | sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= 739 | sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM= 740 | sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w= 741 | sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= 742 | sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= 743 | --------------------------------------------------------------------------------