From 5d20d515a760e4698a707e3297d11416bc32c1b0 Mon Sep 17 00:00:00 2001 From: Dario Tranchitella Date: Tue, 4 Aug 2020 16:30:28 +0200 Subject: [PATCH] Migrating from OperatorSDK 0.18 to 0.19 (#23) --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .gitignore | 86 +- Dockerfile | 31 + Makefile | 129 ++- PROJECT | 10 + README.md | 42 +- .../v1alpha1/domain}/search_in.go | 5 +- .../v1alpha1/groupversion_info.go | 18 +- .../v1alpha1/ingress_class_list.go | 3 + .../v1alpha1/namespace_list.go | 3 + .../v1alpha1/storage_class_list.go | 3 + .../v1alpha1/tenant_annotations.go | 3 + .../capsule => api}/v1alpha1/tenant_func.go | 3 + .../capsule => api}/v1alpha1/tenant_labels.go | 3 + .../capsule => api}/v1alpha1/tenant_types.go | 12 +- .../v1alpha1/zz_generated.deepcopy.go | 29 +- build/Dockerfile | 15 - build/bin/entrypoint | 3 - build/bin/user_setup | 11 - cmd/manager/main.go | 244 ----- .../crd/bases/capsule.clastix.io_tenants.yaml | 702 +++++++++++++++ config/crd/kustomization.yaml | 10 + config/crd/kustomizeconfig.yaml | 17 + config/default/kustomization.yaml | 30 + config/default/manager_auth_proxy_patch.yaml | 25 + config/default/manager_webhook_patch.yaml | 23 + config/manager/kustomization.yaml | 8 + config/manager/manager.yaml | 40 + config/prometheus/kustomization.yaml | 2 + config/prometheus/monitor.yaml | 16 + .../rbac/auth_proxy_client_clusterrole.yaml | 7 + config/rbac/auth_proxy_role.yaml | 13 + config/rbac/auth_proxy_role_binding.yaml | 12 + config/rbac/auth_proxy_service.yaml | 14 + config/rbac/kustomization.yaml | 9 + config/rbac/role_binding.yaml | 12 + .../samples/capsule_v1alpha1_tenant.yaml | 0 config/samples/kustomization.yaml | 3 + config/secret/kustomization.yaml | 3 + config/secret/secret-ca.yaml | 4 + config/secret/secret-tls.yaml | 4 + config/tenants/kustomization.yaml | 3 + .../tenants}/namespace-deleter.yaml | 0 .../tenants}/namespace-provisioner.yaml | 0 config/webhook/kustomization.yaml | 6 + config/webhook/kustomizeconfig.yaml | 25 + config/webhook/manifests.yaml | 122 +++ config/webhook/service.yaml | 11 + contributing.md | 154 ++-- .../namespace_controller.go | 131 ++- controllers/secret/ca.go | 177 ++++ .../secret/const.go | 11 +- .../secret/errors.go | 16 +- controllers/secret/reconciler.go | 75 ++ controllers/secret/tls.go | 127 +++ controllers/suite_test.go | 81 ++ .../tenant_controller.go | 173 ++-- .../crds/capsule.clastix.io_tenants_crd.yaml | 710 --------------- deploy/mutatingwebhookconfiguration.yaml | 96 -- deploy/operator.yaml | 38 - deploy/role.yaml | 44 - deploy/role_binding.yaml | 25 - deploy/secret-ca.yaml | 7 - deploy/secret-tls.yaml | 7 - deploy/service.yaml | 16 - deploy/service_account.yaml | 5 - go.mod | 13 +- go.sum | 840 +----------------- hack/.gitignore | 1 - .../boilerplate.go.txt | 13 +- main.go | 149 ++++ pkg/apis/addtoscheme_capsule_v1alpha1.go | 23 - pkg/apis/capsule/group.go | 19 - pkg/apis/capsule/v1alpha1/doc.go | 17 - pkg/cert/ca.go | 16 + pkg/cert/ca_test.go | 2 +- pkg/cert/errors.go | 16 + pkg/cert/options.go | 16 + pkg/controller/add_namespace.go | 21 - pkg/controller/add_secret.go | 23 - pkg/controller/add_tenant.go | 23 - pkg/controller/controller.go | 31 - pkg/controller/secret/errors.go | 8 - pkg/controller/secret/reconciler.go | 80 -- pkg/controller/secret/secret_ca_controller.go | 180 ---- .../secret/secret_tls_controller.go | 150 ---- pkg/indexer/add_namespaces.go | 3 + pkg/indexer/add_owner.go | 3 + pkg/indexer/indexer.go | 3 + pkg/indexer/tenant/namespaces.go | 5 +- pkg/indexer/tenant/owner.go | 5 +- .../utils/utils.go => utils/user_group.go} | 7 +- pkg/webhook/add_namespace_quota.go | 22 - .../{add_ingress_class.go => handler.go} | 14 +- .../apis.go => webhook/ingress/errors.go} | 23 +- pkg/webhook/ingress/extension.go | 69 ++ .../{ingress_class => ingress}/handler.go | 10 +- pkg/webhook/ingress/networking.go | 67 ++ pkg/webhook/ingress_class/extension.go | 64 -- pkg/webhook/ingress_class/networking.go | 64 -- .../errors.go} | 15 +- pkg/webhook/namespace_quota/validating.go | 50 +- pkg/webhook/network_policies/validating.go | 115 ++- pkg/webhook/owner_reference/patching.go | 78 +- pkg/webhook/pvc/errors.go | 43 + pkg/webhook/pvc/validating.go | 59 +- pkg/webhook/router.go | 82 ++ pkg/webhook/webhook.go | 29 +- tools.go | 5 - version/version.go | 7 +- 110 files changed, 2786 insertions(+), 3366 deletions(-) create mode 100644 Dockerfile create mode 100644 PROJECT rename {pkg/apis/capsule/v1alpha1 => api/v1alpha1/domain}/search_in.go (97%) rename pkg/apis/capsule/v1alpha1/register.go => api/v1alpha1/groupversion_info.go (68%) rename {pkg/apis/capsule => api}/v1alpha1/ingress_class_list.go (99%) rename {pkg/apis/capsule => api}/v1alpha1/namespace_list.go (99%) rename {pkg/apis/capsule => api}/v1alpha1/storage_class_list.go (99%) rename {pkg/apis/capsule => api}/v1alpha1/tenant_annotations.go (99%) rename {pkg/apis/capsule => api}/v1alpha1/tenant_func.go (99%) rename {pkg/apis/capsule => api}/v1alpha1/tenant_labels.go (99%) rename {pkg/apis/capsule => api}/v1alpha1/tenant_types.go (93%) rename {pkg/apis/capsule => api}/v1alpha1/zz_generated.deepcopy.go (89%) delete mode 100644 build/Dockerfile delete mode 100755 build/bin/entrypoint delete mode 100755 build/bin/user_setup delete mode 100644 cmd/manager/main.go create mode 100644 config/crd/bases/capsule.clastix.io_tenants.yaml create mode 100644 config/crd/kustomization.yaml create mode 100644 config/crd/kustomizeconfig.yaml create mode 100644 config/default/kustomization.yaml create mode 100644 config/default/manager_auth_proxy_patch.yaml create mode 100644 config/default/manager_webhook_patch.yaml create mode 100644 config/manager/kustomization.yaml create mode 100644 config/manager/manager.yaml create mode 100644 config/prometheus/kustomization.yaml create mode 100644 config/prometheus/monitor.yaml create mode 100644 config/rbac/auth_proxy_client_clusterrole.yaml create mode 100644 config/rbac/auth_proxy_role.yaml create mode 100644 config/rbac/auth_proxy_role_binding.yaml create mode 100644 config/rbac/auth_proxy_service.yaml create mode 100644 config/rbac/kustomization.yaml create mode 100644 config/rbac/role_binding.yaml rename deploy/crds/capsule.clastix.io_v1alpha1_tenant_cr.yaml => config/samples/capsule_v1alpha1_tenant.yaml (100%) create mode 100644 config/samples/kustomization.yaml create mode 100644 config/secret/kustomization.yaml create mode 100644 config/secret/secret-ca.yaml create mode 100644 config/secret/secret-tls.yaml create mode 100644 config/tenants/kustomization.yaml rename {deploy => config/tenants}/namespace-deleter.yaml (100%) rename {deploy => config/tenants}/namespace-provisioner.yaml (100%) create mode 100644 config/webhook/kustomization.yaml create mode 100644 config/webhook/kustomizeconfig.yaml create mode 100644 config/webhook/manifests.yaml create mode 100644 config/webhook/service.yaml rename {pkg/controller/namespace => controllers}/namespace_controller.go (52%) create mode 100644 controllers/secret/ca.go rename {pkg/controller => controllers}/secret/const.go (81%) rename pkg/webhook/add_pvc.go => controllers/secret/errors.go (79%) create mode 100644 controllers/secret/reconciler.go create mode 100644 controllers/secret/tls.go create mode 100644 controllers/suite_test.go rename {pkg/controller/tenant => controllers}/tenant_controller.go (68%) delete mode 100644 deploy/crds/capsule.clastix.io_tenants_crd.yaml delete mode 100644 deploy/mutatingwebhookconfiguration.yaml delete mode 100644 deploy/operator.yaml delete mode 100644 deploy/role.yaml delete mode 100644 deploy/role_binding.yaml delete mode 100644 deploy/secret-ca.yaml delete mode 100644 deploy/secret-tls.yaml delete mode 100644 deploy/service.yaml delete mode 100644 deploy/service_account.yaml delete mode 100644 hack/.gitignore rename pkg/webhook/add_owner_reference.go => hack/boilerplate.go.txt (76%) create mode 100644 main.go delete mode 100644 pkg/apis/addtoscheme_capsule_v1alpha1.go delete mode 100644 pkg/apis/capsule/group.go delete mode 100644 pkg/apis/capsule/v1alpha1/doc.go delete mode 100644 pkg/controller/add_namespace.go delete mode 100644 pkg/controller/add_secret.go delete mode 100644 pkg/controller/add_tenant.go delete mode 100644 pkg/controller/controller.go delete mode 100644 pkg/controller/secret/errors.go delete mode 100644 pkg/controller/secret/reconciler.go delete mode 100644 pkg/controller/secret/secret_ca_controller.go delete mode 100644 pkg/controller/secret/secret_tls_controller.go rename pkg/{webhook/utils/utils.go => utils/user_group.go} (91%) delete mode 100644 pkg/webhook/add_namespace_quota.go rename pkg/webhook/{add_ingress_class.go => handler.go} (53%) rename pkg/{apis/apis.go => webhook/ingress/errors.go} (62%) create mode 100644 pkg/webhook/ingress/extension.go rename pkg/webhook/{ingress_class => ingress}/handler.go (87%) create mode 100644 pkg/webhook/ingress/networking.go delete mode 100644 pkg/webhook/ingress_class/extension.go delete mode 100644 pkg/webhook/ingress_class/networking.go rename pkg/webhook/{add_network_policy.go => namespace_quota/errors.go} (65%) create mode 100644 pkg/webhook/pvc/errors.go create mode 100644 pkg/webhook/router.go delete mode 100644 tools.go diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 70be8b4a..d931afad 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -35,7 +35,7 @@ A clear and concise description of what you expected to happen. If applicable, please provide logs of `capsule`. In a standard stand-alone installation of Capsule, -you'd get this by running `kubectl -n capsule-system logs deploy/capsule`. +you'd get this by running `kubectl -n capsule-system logs deploy/capsule-controller-manager`. # Additional context diff --git a/.gitignore b/.gitignore index 89f9c4ba..b502e0e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,78 +1,26 @@ -# Temporary Build Files -build/_output -build/_test -# Created by https://www.gitignore.io/api/go,vim,emacs,visualstudiocode -### Emacs ### -# -*- mode: gitignore; -*- -*~ -\#*\# -/.emacs.desktop -/.emacs.desktop.lock -*.elc -auto-save-list -tramp -.\#* -# Org-mode -.org-id-locations -*_archive -# flymake-mode -*_flymake.* -# eshell files -/eshell/history -/eshell/lastdir -# elpa packages -/elpa/ -# reftex files -*.rel -# AUCTeX auto folder -/auto/ -# cask packages -.cask/ -dist/ -# Flycheck -flycheck_*.el -# server auth directory -/server/ -# projectiles files -.projectile -projectile-bookmarks.eld -# directory configuration -.dir-locals.el -# saveplace -places -# url cache -url/cache/ -# cedet -ede-projects.el -# smex -smex-items -# company-statistics -company-statistics-cache.el -# anaconda-mode -anaconda-mode/ -### Go ### + # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib -# Test binary, build with 'go test -c' +bin + +# Test binary, build with `go test -c` *.test + # Output of the go coverage tool, specifically when used with LiteIDE *.out -### Vim ### -# swap -.sw[a-p] -.*.sw[a-p] -# session -Session.vim -# temporary -.netrwhist -# auto-generated tag files -tags -### VisualStudioCode ### -.vscode/* -.history -# End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode -.idea \ No newline at end of file + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ + +hack/*.kubeconfig diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..c41ab059 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# Build the manager binary +FROM golang:1.13 as builder + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the go source +COPY main.go main.go +COPY api/ api/ +COPY controllers/ controllers/ +COPY pkg/ pkg/ +COPY version/ version/ + +ARG VERSION + +# Build +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -ldflags "-X github.com/clastix/capsule/version.Version=${VERSION}" -o manager main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/static:nonroot +WORKDIR / +COPY --from=builder /workspace/manager . +USER nonroot:nonroot + +ENTRYPOINT ["/manager"] diff --git a/Makefile b/Makefile index c1fb3cf0..301ea071 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,118 @@ -.PHONY: k8s -k8s: - operator-sdk generate k8s +# Current Operator version +VERSION ?= 0.0.1 -.PHONY: crds -crds: - operator-sdk generate crds +# Default bundle image tag +BUNDLE_IMG ?= quay.io/clastix/capsule:$(VERSION)-bundle +# Options for 'bundle-build' +ifneq ($(origin CHANNELS), undefined) +BUNDLE_CHANNELS := --channels=$(CHANNELS) +endif +ifneq ($(origin DEFAULT_CHANNEL), undefined) +BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) +endif +BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) -.PHONY: docker-image -docker-image: - operator-sdk build quay.io/clastix/capsule:latest +# Image URL to use all building/pushing image targets +IMG ?= quay.io/clastix/capsule:latest +# Produce CRDs that work back to Kubernetes 1.11 (no version conversion) +CRD_OPTIONS ?= "crd:trivialVersions=true" -.PHONY: goimports -goimports: - goimports -w -l -local "github.com/clastix/capsule" . +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif -.PHONY: golint -golint: - golangci-lint run +all: manager + +# Run tests +test: generate fmt vet manifests + go test ./... -coverprofile cover.out + +# Build manager binary +manager: generate fmt vet + go build -o bin/manager main.go + +# Run against the configured Kubernetes cluster in ~/.kube/config +run: generate fmt vet manifests + go run ./main.go + +# Install CRDs into a cluster +install: manifests kustomize + $(KUSTOMIZE) build config/crd | kubectl apply -f - + +# Uninstall CRDs from a cluster +uninstall: manifests kustomize + $(KUSTOMIZE) build config/crd | kubectl delete -f - + +# Deploy controller in the configured Kubernetes cluster in ~/.kube/config +deploy: manifests kustomize + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + $(KUSTOMIZE) build config/default | kubectl apply -f - + +# Generate manifests e.g. CRD, RBAC etc. +manifests: controller-gen + $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases + +# Run go fmt against code +fmt: + go fmt ./... + +# Run go vet against code +vet: + go vet ./... + +# Generate code +generate: controller-gen + $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." + +# Build the docker image +docker-build: test + docker build . --build-arg=VERSION=${VERSION} -t ${IMG} + +# Push the docker image +docker-push: + docker push ${IMG} + +# find or download controller-gen +# download controller-gen if necessary +controller-gen: +ifeq (, $(shell which controller-gen)) + @{ \ + set -e ;\ + CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ + cd $$CONTROLLER_GEN_TMP_DIR ;\ + go mod init tmp ;\ + go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.3.0 ;\ + rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ + } +CONTROLLER_GEN=$(GOBIN)/controller-gen +else +CONTROLLER_GEN=$(shell which controller-gen) +endif + +kustomize: +ifeq (, $(shell which kustomize)) + @{ \ + set -e ;\ + KUSTOMIZE_GEN_TMP_DIR=$$(mktemp -d) ;\ + cd $$KUSTOMIZE_GEN_TMP_DIR ;\ + go mod init tmp ;\ + go get sigs.k8s.io/kustomize/kustomize/v3@v3.5.4 ;\ + rm -rf $$KUSTOMIZE_GEN_TMP_DIR ;\ + } +KUSTOMIZE=$(GOBIN)/kustomize +else +KUSTOMIZE=$(shell which kustomize) +endif + +# Generate bundle manifests and metadata, then validate generated files. +bundle: manifests + operator-sdk generate kustomize manifests -q + kustomize build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + operator-sdk bundle validate ./bundle + +# Build the bundle image. +bundle-build: + docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . diff --git a/PROJECT b/PROJECT new file mode 100644 index 00000000..731fd830 --- /dev/null +++ b/PROJECT @@ -0,0 +1,10 @@ +domain: github.com/clastix/capsule +layout: go.kubebuilder.io/v2 +repo: github.com/clastix/capsule +resources: +- group: capsule.clastix.io + kind: Tenant + version: v1alpha1 +version: 3-alpha +plugins: + go.operator-sdk.io/v2-alpha: {} diff --git a/README.md b/README.md index 5548c803..bde078b6 100644 --- a/README.md +++ b/README.md @@ -8,24 +8,30 @@ _Container-as-a-Service_ (CaaS) platforms. # tl;dr; How to install -As a Cluster Admin, ensure the `capsule-system` Namespace is already there. +Ensure you have [`kustomize`](https://github.com/kubernetes-sigs/kustomize) +installed in your `PATH`: ``` -# kubectl apply -f deploy -mutatingwebhookconfiguration.admissionregistration.k8s.io/capsule created -clusterrole.rbac.authorization.k8s.io/namespace:deleter created -clusterrole.rbac.authorization.k8s.io/namespace:provisioner created -clusterrolebinding.rbac.authorization.k8s.io/namespace:provisioner created -deployment.apps/capsule created -clusterrole.rbac.authorization.k8s.io/capsule created -clusterrolebinding.rbac.authorization.k8s.io/capsule-cluster-admin created -clusterrolebinding.rbac.authorization.k8s.io/capsule created -secret/capsule-ca created -secret/capsule-tls created -service/capsule created -serviceaccount/capsule created -# kubectl apply -f deploy/crds/capsule.clastix.io_tenants_crd.yaml -customresourcedefinition.apiextensions.k8s.io/tenants.capsule.clastix.io created +make deploy +# /home/prometherion/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases +# cd config/manager && /usr/local/bin/kustomize edit set image controller=quay.io/clastix/capsule:latest +# /usr/local/bin/kustomize build config/default | kubectl apply -f - +# namespace/capsule-system created +# customresourcedefinition.apiextensions.k8s.io/tenants.capsule.clastix.io created +# clusterrole.rbac.authorization.k8s.io/capsule-namespace:deleter created +# clusterrole.rbac.authorization.k8s.io/capsule-namespace:provisioner created +# clusterrole.rbac.authorization.k8s.io/capsule-proxy-role created +# clusterrole.rbac.authorization.k8s.io/capsule-metrics-reader created +# clusterrolebinding.rbac.authorization.k8s.io/capsule-manager-rolebinding created +# clusterrolebinding.rbac.authorization.k8s.io/capsule-namespace:provisioner created +# clusterrolebinding.rbac.authorization.k8s.io/capsule-proxy-rolebinding created +# secret/capsule-ca created +# secret/capsule-tls created +# service/capsule-controller-manager-metrics-service created +# service/capsule-webhook-service created +# deployment.apps/capsule-controller-manager created +# mutatingwebhookconfiguration.admissionregistration.k8s.io/capsule-mutating-webhook-configuration created +# validatingwebhookconfiguration.admissionregistration.k8s.io/capsule-validating-webhook-configuration created ``` ## Webhooks and CA Bundle @@ -64,11 +70,11 @@ All Tenant owner needs to be granted with a X.509 certificate with ## How to create a Tenant -Use the [scaffold Tenant](deploy/crds/capsule.clastix.io_v1alpha1_tenant_cr.yaml) +Use the [scaffold Tenant](config/samples/capsule_v1alpha1_tenant.yaml) and simply apply as Cluster Admin. ``` -# kubectl apply -f deploy/crds/capsule.clastix.io_v1alpha1_tenant_cr.yaml +# kubectl apply -f config/samples/capsule_v1alpha1_tenant.yaml tenant.capsule.clastix.io/oil created ``` diff --git a/pkg/apis/capsule/v1alpha1/search_in.go b/api/v1alpha1/domain/search_in.go similarity index 97% rename from pkg/apis/capsule/v1alpha1/search_in.go rename to api/v1alpha1/domain/search_in.go index b1b56956..30cd4a2e 100644 --- a/pkg/apis/capsule/v1alpha1/search_in.go +++ b/api/v1alpha1/domain/search_in.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package domain type SearchIn interface { IsStringInList(value string) bool diff --git a/pkg/apis/capsule/v1alpha1/register.go b/api/v1alpha1/groupversion_info.go similarity index 68% rename from pkg/apis/capsule/v1alpha1/register.go rename to api/v1alpha1/groupversion_info.go index 6d708f58..b0eb8eac 100644 --- a/pkg/apis/capsule/v1alpha1/register.go +++ b/api/v1alpha1/groupversion_info.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,10 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -// NOTE: Boilerplate only. Ignore this file. - -// Package v1alpha1 contains API Schema definitions for the capsule v1alpha1 API group -// +k8s:deepcopy-gen=package,register +// Package v1alpha1 contains API Schema definitions for the capsule.clastix.io v1alpha1 API group +// +kubebuilder:object:generate=true // +groupName=capsule.clastix.io package v1alpha1 @@ -24,9 +25,12 @@ import ( ) var ( - // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: "capsule.clastix.io", Version: "v1alpha1"} + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "capsule.clastix.io", Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/pkg/apis/capsule/v1alpha1/ingress_class_list.go b/api/v1alpha1/ingress_class_list.go similarity index 99% rename from pkg/apis/capsule/v1alpha1/ingress_class_list.go rename to api/v1alpha1/ingress_class_list.go index e54ae889..0ba12d22 100644 --- a/pkg/apis/capsule/v1alpha1/ingress_class_list.go +++ b/api/v1alpha1/ingress_class_list.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/capsule/v1alpha1/namespace_list.go b/api/v1alpha1/namespace_list.go similarity index 99% rename from pkg/apis/capsule/v1alpha1/namespace_list.go rename to api/v1alpha1/namespace_list.go index f56f1ced..45954795 100644 --- a/pkg/apis/capsule/v1alpha1/namespace_list.go +++ b/api/v1alpha1/namespace_list.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/capsule/v1alpha1/storage_class_list.go b/api/v1alpha1/storage_class_list.go similarity index 99% rename from pkg/apis/capsule/v1alpha1/storage_class_list.go rename to api/v1alpha1/storage_class_list.go index e8cb3515..d7781761 100644 --- a/pkg/apis/capsule/v1alpha1/storage_class_list.go +++ b/api/v1alpha1/storage_class_list.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/capsule/v1alpha1/tenant_annotations.go b/api/v1alpha1/tenant_annotations.go similarity index 99% rename from pkg/apis/capsule/v1alpha1/tenant_annotations.go rename to api/v1alpha1/tenant_annotations.go index 7706fc58..100d4ebc 100644 --- a/pkg/apis/capsule/v1alpha1/tenant_annotations.go +++ b/api/v1alpha1/tenant_annotations.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/capsule/v1alpha1/tenant_func.go b/api/v1alpha1/tenant_func.go similarity index 99% rename from pkg/apis/capsule/v1alpha1/tenant_func.go rename to api/v1alpha1/tenant_func.go index c4ed8af1..fd87483d 100644 --- a/pkg/apis/capsule/v1alpha1/tenant_func.go +++ b/api/v1alpha1/tenant_func.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/capsule/v1alpha1/tenant_labels.go b/api/v1alpha1/tenant_labels.go similarity index 99% rename from pkg/apis/capsule/v1alpha1/tenant_labels.go rename to api/v1alpha1/tenant_labels.go index 9f8ac0e6..e384bab6 100644 --- a/pkg/apis/capsule/v1alpha1/tenant_labels.go +++ b/api/v1alpha1/tenant_labels.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/apis/capsule/v1alpha1/tenant_types.go b/api/v1alpha1/tenant_types.go similarity index 93% rename from pkg/apis/capsule/v1alpha1/tenant_types.go rename to api/v1alpha1/tenant_types.go index 48ca27da..ef16d6c1 100644 --- a/pkg/apis/capsule/v1alpha1/tenant_types.go +++ b/api/v1alpha1/tenant_types.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -45,12 +48,13 @@ type TenantStatus struct { Groups []string `json:"groups,omitempty"` } -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// Tenant is the Schema for the tenants API +// +kubebuilder:object:root=true // +kubebuilder:subresource:status -// +kubebuilder:resource:path=tenants,scope=Cluster +// +kubebuilder:resource:scope=Cluster // +kubebuilder:printcolumn:name="Namespace quota",type="integer",JSONPath=".spec.namespaceQuota",description="The max amount of Namespaces can be created" // +kubebuilder:printcolumn:name="Namespace count",type="integer",JSONPath=".status.size",description="The total amount of Namespaces in use" + +// Tenant is the Schema for the tenants API type Tenant struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -59,7 +63,7 @@ type Tenant struct { Status TenantStatus `json:"status,omitempty"` } -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true // TenantList contains a list of Tenant type TenantList struct { diff --git a/pkg/apis/capsule/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go similarity index 89% rename from pkg/apis/capsule/v1alpha1/zz_generated.deepcopy.go rename to api/v1alpha1/zz_generated.deepcopy.go index 45be213d..5f65bfb9 100644 --- a/pkg/apis/capsule/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,13 +1,29 @@ // +build !ignore_autogenerated -// Code generated by operator-sdk. DO NOT EDIT. +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. package v1alpha1 import ( corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/networking/v1" - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/api/networking/v1" + "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -16,7 +32,6 @@ func (in IngressClassList) DeepCopyInto(out *IngressClassList) { in := &in *out = make(IngressClassList, len(*in)) copy(*out, *in) - return } } @@ -36,7 +51,6 @@ func (in NamespaceList) DeepCopyInto(out *NamespaceList) { in := &in *out = make(NamespaceList, len(*in)) copy(*out, *in) - return } } @@ -56,7 +70,6 @@ func (in StorageClassList) DeepCopyInto(out *StorageClassList) { in := &in *out = make(StorageClassList, len(*in)) copy(*out, *in) - return } } @@ -77,7 +90,6 @@ func (in *Tenant) DeepCopyInto(out *Tenant) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Tenant. @@ -110,7 +122,6 @@ func (in *TenantList) DeepCopyInto(out *TenantList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantList. @@ -172,7 +183,6 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantSpec. @@ -203,7 +213,6 @@ func (in *TenantStatus) DeepCopyInto(out *TenantStatus) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TenantStatus. diff --git a/build/Dockerfile b/build/Dockerfile deleted file mode 100644 index 0f4cc6f9..00000000 --- a/build/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM registry.access.redhat.com/ubi8/ubi-minimal:latest - -ENV OPERATOR=/usr/local/bin/capsule \ - USER_UID=0 \ - USER_NAME=capsule - -# install operator binary -COPY build/_output/bin/capsule ${OPERATOR} - -COPY build/bin /usr/local/bin -RUN /usr/local/bin/user_setup - -ENTRYPOINT ["/usr/local/bin/entrypoint"] - -USER ${USER_UID} diff --git a/build/bin/entrypoint b/build/bin/entrypoint deleted file mode 100755 index 457186bd..00000000 --- a/build/bin/entrypoint +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -e - -exec ${OPERATOR} $@ diff --git a/build/bin/user_setup b/build/bin/user_setup deleted file mode 100755 index 4b5b77d6..00000000 --- a/build/bin/user_setup +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -set -x - -# ensure $HOME exists and is accessible by group 0 (we don't know what the runtime UID will be) -echo "${USER_NAME}:x:${USER_UID}:0:${USER_NAME} user:${HOME}:/sbin/nologin" >> /etc/passwd -mkdir -p "${HOME}" -chown "${USER_UID}:0" "${HOME}" -chmod ug+rwx "${HOME}" - -# no need for this script to remain in the image after running -rm "$0" diff --git a/cmd/manager/main.go b/cmd/manager/main.go deleted file mode 100644 index ee97091a..00000000 --- a/cmd/manager/main.go +++ /dev/null @@ -1,244 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "os" - "runtime" - "strings" - - "github.com/operator-framework/operator-sdk/pkg/k8sutil" - kubemetrics "github.com/operator-framework/operator-sdk/pkg/kube-metrics" - "github.com/operator-framework/operator-sdk/pkg/leader" - "github.com/operator-framework/operator-sdk/pkg/log/zap" - "github.com/operator-framework/operator-sdk/pkg/metrics" - sdkVersion "github.com/operator-framework/operator-sdk/version" - "github.com/spf13/pflag" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/intstr" - _ "k8s.io/client-go/plugin/pkg/client/auth" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/cache" - "sigs.k8s.io/controller-runtime/pkg/client/config" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/manager/signals" - - "github.com/clastix/capsule/pkg/apis" - "github.com/clastix/capsule/pkg/controller" - "github.com/clastix/capsule/pkg/indexer" - "github.com/clastix/capsule/pkg/webhook" - "github.com/clastix/capsule/version" -) - -// Change below variables to serve metrics on different host or port. -var ( - metricsHost = "0.0.0.0" - metricsPort int32 = 8383 - operatorMetricsPort int32 = 8686 -) -var log = logf.Log.WithName("cmd") - -func printVersion() { - log.Info(fmt.Sprintf("Operator Version: %s", version.Version)) - log.Info(fmt.Sprintf("Go Version: %s", runtime.Version())) - log.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH)) - log.Info(fmt.Sprintf("Version of operator-sdk: %v", sdkVersion.Version)) -} - -func main() { - // Add the zap logger flag set to the CLI. The flag set must - // be added before calling pflag.Parse(). - pflag.CommandLine.AddFlagSet(zap.FlagSet()) - - // Add flags registered by imported packages (e.g. glog and - // controller-runtime) - pflag.CommandLine.AddGoFlagSet(flag.CommandLine) - - var v bool - pflag.BoolVarP(&v, "version", "v", false, "Print the Capsule version and exit") - - pflag.Parse() - - // Use a zap logr.Logger implementation. If none of the zap - // flags are configured (or if the zap flag set is not being - // used), this defaults to a production zap logger. - // - // The logger instantiated here can be changed to any logger - // implementing the logr.Logger interface. This logger will - // be propagated through the whole operator, generating - // uniform and structured logs. - logf.SetLogger(zap.Logger()) - - printVersion() - if v { - os.Exit(0) - } - - namespace, err := k8sutil.GetWatchNamespace() - if err != nil { - log.Error(err, "Failed to get watch namespace") - os.Exit(1) - } - - // Get a config to talk to the apiserver - cfg, err := config.GetConfig() - if err != nil { - log.Error(err, "") - os.Exit(1) - } - - ctx := context.TODO() - // Become the leader before proceeding - err = leader.Become(ctx, "capsule-lock") - if err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Set default manager options - options := manager.Options{ - Namespace: namespace, - MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort), - } - - // Add support for MultiNamespace set in WATCH_NAMESPACE (e.g ns1,ns2) - // Note that this is not intended to be used for excluding namespaces, this is better done via a Predicate - // Also note that you may face performance issues when using this with a high number of namespaces. - // More Info: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/cache#MultiNamespacedCacheBuilder - if strings.Contains(namespace, ",") { - options.Namespace = "" - options.NewCache = cache.MultiNamespacedCacheBuilder(strings.Split(namespace, ",")) - } - - stop := signals.SetupSignalHandler() - - // Create a new manager to provide shared dependencies and start components - mgr, err := manager.New(cfg, options) - if err != nil { - log.Error(err, "") - os.Exit(1) - } - - log.Info("Registering Components.") - - // Setup Scheme for all resources - if err := apis.AddToScheme(mgr.GetScheme()); err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Setup all Controllers - if err := controller.AddToManager(mgr); err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Setup all Webhooks - if err := webhook.AddToServer(mgr); err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Setup all Custom Indexers - if err := indexer.AddToManager(mgr); err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Add the Metrics Service - addMetrics(ctx, cfg) - - log.Info("Starting the Cmd.") - - // Start the Cmd - if err := mgr.Start(stop); err != nil { - log.Error(err, "Manager exited non-zero") - os.Exit(1) - } -} - -// addMetrics will create the Services and Service Monitors to allow the operator export the metrics by using -// the Prometheus operator -func addMetrics(ctx context.Context, cfg *rest.Config) { - // Get the namespace the operator is currently deployed in. - operatorNs, err := k8sutil.GetOperatorNamespace() - if err != nil { - if errors.Is(err, k8sutil.ErrRunLocal) { - log.Info("Skipping CR metrics server creation; not running in a cluster.") - return - } - } - - if err := serveCRMetrics(cfg, operatorNs); err != nil { - log.Info("Could not generate and serve custom resource metrics", "error", err.Error()) - } - - // Add to the below struct any other metrics ports you want to expose. - servicePorts := []v1.ServicePort{ - {Port: metricsPort, Name: metrics.OperatorPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: metricsPort}}, - {Port: operatorMetricsPort, Name: metrics.CRPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: operatorMetricsPort}}, - } - - // Create Service object to expose the metrics port(s). - service, err := metrics.CreateMetricsService(ctx, cfg, servicePorts) - if err != nil { - log.Info("Could not create metrics Service", "error", err.Error()) - } - - // CreateServiceMonitors will automatically create the prometheus-operator ServiceMonitor resources - // necessary to configure Prometheus to scrape metrics from this operator. - services := []*v1.Service{service} - - // The ServiceMonitor is created in the same namespace where the operator is deployed - _, err = metrics.CreateServiceMonitors(cfg, operatorNs, services) - if err != nil { - log.Info("Could not create ServiceMonitor object", "error", err.Error()) - // If this operator is deployed to a cluster without the prometheus-operator running, it will return - // ErrServiceMonitorNotPresent, which can be used to safely skip ServiceMonitor creation. - if err == metrics.ErrServiceMonitorNotPresent { - log.Info("Install prometheus-operator in your cluster to create ServiceMonitor objects", "error", err.Error()) - } - } -} - -// serveCRMetrics gets the Operator/CustomResource GVKs and generates metrics based on those types. -// It serves those metrics on "http://metricsHost:operatorMetricsPort". -func serveCRMetrics(cfg *rest.Config, operatorNs string) error { - // The function below returns a list of filtered operator/CR specific GVKs. For more control, override the GVK list below - // with your own custom logic. Note that if you are adding third party API schemas, probably you will need to - // customize this implementation to avoid permissions issues. - filteredGVK, err := k8sutil.GetGVKsFromAddToScheme(apis.AddToScheme) - if err != nil { - return err - } - - // The metrics will be generated from the namespaces which are returned here. - // NOTE that passing nil or an empty list of namespaces in GenerateAndServeCRMetrics will result in an error. - ns, err := kubemetrics.GetNamespacesForMetrics(operatorNs) - if err != nil { - return err - } - - // Generate and serve custom resource specific metrics. - err = kubemetrics.GenerateAndServeCRMetrics(cfg, ns, filteredGVK, metricsHost, operatorMetricsPort) - if err != nil { - return err - } - return nil -} diff --git a/config/crd/bases/capsule.clastix.io_tenants.yaml b/config/crd/bases/capsule.clastix.io_tenants.yaml new file mode 100644 index 00000000..ec593bd8 --- /dev/null +++ b/config/crd/bases/capsule.clastix.io_tenants.yaml @@ -0,0 +1,702 @@ + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.5 + creationTimestamp: null + name: tenants.capsule.clastix.io +spec: + additionalPrinterColumns: + - JSONPath: .spec.namespaceQuota + description: The max amount of Namespaces can be created + name: Namespace quota + type: integer + - JSONPath: .status.size + description: The total amount of Namespaces in use + name: Namespace count + type: integer + group: capsule.clastix.io + names: + kind: Tenant + listKind: TenantList + plural: tenants + singular: tenant + scope: Cluster + subresources: + status: {} + validation: + openAPIV3Schema: + description: Tenant is the Schema for the tenants API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: TenantSpec defines the desired state of Tenant + properties: + ingressClasses: + items: + type: string + type: array + limitRanges: + items: + description: LimitRangeSpec defines a min/max usage limit for resources + that match on kind. + properties: + limits: + description: Limits is the list of LimitRangeItem objects that + are enforced. + items: + description: LimitRangeItem defines a min/max usage limit for + any resource that matches on kind. + properties: + default: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Default resource requirement limit value by + resource name if resource limit is omitted. + type: object + defaultRequest: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: DefaultRequest is the default resource requirement + request value by resource name if resource request is + omitted. + type: object + max: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Max usage constraints on this kind by resource + name. + type: object + maxLimitRequestRatio: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: MaxLimitRequestRatio if specified, the named + resource must have a request and limit that are both non-zero + where limit divided by request is less than or equal to + the enumerated value; this represents the max burst for + the named resource. + type: object + min: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Min usage constraints on this kind by resource + name. + type: object + type: + description: Type of resource that this limit applies to. + type: string + required: + - type + type: object + type: array + required: + - limits + type: object + type: array + namespaceQuota: + minimum: 1 + type: integer + networkPolicies: + items: + description: NetworkPolicySpec provides the specification of a NetworkPolicy + properties: + egress: + description: List of egress rules to be applied to the selected + pods. Outgoing traffic is allowed if there are no NetworkPolicies + selecting the pod (and cluster policy otherwise allows the traffic), + OR if the traffic matches at least one egress rule across all + of the NetworkPolicy objects whose podSelector matches the pod. + If this field is empty then this NetworkPolicy limits all outgoing + traffic (and serves solely to ensure that the pods it selects + are isolated by default). This field is beta-level in 1.8 + items: + description: NetworkPolicyEgressRule describes a particular + set of traffic that is allowed out of pods matched by a NetworkPolicySpec's + podSelector. The traffic must match both ports and to. This + type is beta-level in 1.8 + properties: + ports: + description: List of destination ports for outgoing traffic. + Each item in this list is combined using a logical OR. + If this field is empty or missing, this rule matches all + ports (traffic not restricted by port). If this field + is present and contains at least one item, then this rule + allows traffic only if the traffic matches at least one + port in the list. + items: + description: NetworkPolicyPort describes a port to allow + traffic on + properties: + port: + anyOf: + - type: integer + - type: string + description: The port on the given protocol. This + can either be a numerical or named port on a pod. + If this field is not provided, this matches all + port names and numbers. + x-kubernetes-int-or-string: true + protocol: + description: The protocol (TCP, UDP, or SCTP) which + traffic must match. If not specified, this field + defaults to TCP. + type: string + type: object + type: array + to: + description: List of destinations for outgoing traffic of + pods selected for this rule. Items in this list are combined + using a logical OR operation. If this field is empty or + missing, this rule matches all destinations (traffic not + restricted by destination). If this field is present and + contains at least one item, this rule allows traffic only + if the traffic matches at least one item in the to list. + items: + description: NetworkPolicyPeer describes a peer to allow + traffic from. Only certain combinations of fields are + allowed + properties: + ipBlock: + description: IPBlock defines policy on a particular + IPBlock. If this field is set then neither of the + other fields can be. + properties: + cidr: + description: CIDR is a string representing the + IP Block Valid examples are "192.168.1.1/24" + or "2001:db9::/64" + type: string + except: + description: Except is a slice of CIDRs that should + not be included within an IP Block Valid examples + are "192.168.1.1/24" or "2001:db9::/64" Except + values will be rejected if they are outside + the CIDR range + items: + type: string + type: array + required: + - cidr + type: object + namespaceSelector: + description: "Selects Namespaces using cluster-scoped + labels. This field follows standard label selector + semantics; if present but empty, it selects all + namespaces. \n If PodSelector is also set, then + the NetworkPolicyPeer as a whole selects the Pods + matching PodSelector in the Namespaces selected + by NamespaceSelector. Otherwise it selects all Pods + in the Namespaces selected by NamespaceSelector." + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + podSelector: + description: "This is a label selector which selects + Pods. This field follows standard label selector + semantics; if present but empty, it selects all + pods. \n If NamespaceSelector is also set, then + the NetworkPolicyPeer as a whole selects the Pods + matching PodSelector in the Namespaces selected + by NamespaceSelector. Otherwise it selects the Pods + matching PodSelector in the policy's own Namespace." + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + type: object + type: array + type: object + type: array + ingress: + description: List of ingress rules to be applied to the selected + pods. Traffic is allowed to a pod if there are no NetworkPolicies + selecting the pod (and cluster policy otherwise allows the traffic), + OR if the traffic source is the pod's local node, OR if the + traffic matches at least one ingress rule across all of the + NetworkPolicy objects whose podSelector matches the pod. If + this field is empty then this NetworkPolicy does not allow any + traffic (and serves solely to ensure that the pods it selects + are isolated by default) + items: + description: NetworkPolicyIngressRule describes a particular + set of traffic that is allowed to the pods matched by a NetworkPolicySpec's + podSelector. The traffic must match both ports and from. + properties: + from: + description: List of sources which should be able to access + the pods selected for this rule. Items in this list are + combined using a logical OR operation. If this field is + empty or missing, this rule matches all sources (traffic + not restricted by source). If this field is present and + contains at least one item, this rule allows traffic only + if the traffic matches at least one item in the from list. + items: + description: NetworkPolicyPeer describes a peer to allow + traffic from. Only certain combinations of fields are + allowed + properties: + ipBlock: + description: IPBlock defines policy on a particular + IPBlock. If this field is set then neither of the + other fields can be. + properties: + cidr: + description: CIDR is a string representing the + IP Block Valid examples are "192.168.1.1/24" + or "2001:db9::/64" + type: string + except: + description: Except is a slice of CIDRs that should + not be included within an IP Block Valid examples + are "192.168.1.1/24" or "2001:db9::/64" Except + values will be rejected if they are outside + the CIDR range + items: + type: string + type: array + required: + - cidr + type: object + namespaceSelector: + description: "Selects Namespaces using cluster-scoped + labels. This field follows standard label selector + semantics; if present but empty, it selects all + namespaces. \n If PodSelector is also set, then + the NetworkPolicyPeer as a whole selects the Pods + matching PodSelector in the Namespaces selected + by NamespaceSelector. Otherwise it selects all Pods + in the Namespaces selected by NamespaceSelector." + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + podSelector: + description: "This is a label selector which selects + Pods. This field follows standard label selector + semantics; if present but empty, it selects all + pods. \n If NamespaceSelector is also set, then + the NetworkPolicyPeer as a whole selects the Pods + matching PodSelector in the Namespaces selected + by NamespaceSelector. Otherwise it selects the Pods + matching PodSelector in the policy's own Namespace." + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement is + a selector that contains values, a key, and + an operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If + the operator is Exists or DoesNotExist, + the values array must be empty. This array + is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + type: object + type: array + ports: + description: List of ports which should be made accessible + on the pods selected for this rule. Each item in this + list is combined using a logical OR. If this field is + empty or missing, this rule matches all ports (traffic + not restricted by port). If this field is present and + contains at least one item, then this rule allows traffic + only if the traffic matches at least one port in the list. + items: + description: NetworkPolicyPort describes a port to allow + traffic on + properties: + port: + anyOf: + - type: integer + - type: string + description: The port on the given protocol. This + can either be a numerical or named port on a pod. + If this field is not provided, this matches all + port names and numbers. + x-kubernetes-int-or-string: true + protocol: + description: The protocol (TCP, UDP, or SCTP) which + traffic must match. If not specified, this field + defaults to TCP. + type: string + type: object + type: array + type: object + type: array + podSelector: + description: Selects the pods to which this NetworkPolicy object + applies. The array of ingress rules is applied to any pods selected + by this field. Multiple network policies can select the same + set of pods. In this case, the ingress rules for each are combined + additively. This field is NOT optional and follows standard + label selector semantics. An empty podSelector matches all pods + in this namespace. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A + single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is "key", + the operator is "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + policyTypes: + description: List of rule types that the NetworkPolicy relates + to. Valid options are "Ingress", "Egress", or "Ingress,Egress". + If this field is not specified, it will default based on the + existence of Ingress or Egress rules; policies that contain + an Egress section are assumed to affect Egress, and all policies + (whether or not they contain an Ingress section) are assumed + to affect Ingress. If you want to write an egress-only policy, + you must explicitly specify policyTypes [ "Egress" ]. Likewise, + if you want to write a policy that specifies that no egress + is allowed, you must specify a policyTypes value that include + "Egress" (since such a policy would not include an Egress section + and would otherwise default to just [ "Ingress" ]). This field + is beta-level in 1.8 + items: + description: Policy Type string describes the NetworkPolicy + type This type is beta-level in 1.8 + type: string + type: array + required: + - podSelector + type: object + type: array + nodeSelector: + additionalProperties: + type: string + type: object + owner: + type: string + resourceQuotas: + items: + description: ResourceQuotaSpec defines the desired hard limits to + enforce for Quota. + properties: + hard: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'hard is the set of desired hard limits for each + named resource. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/' + type: object + scopeSelector: + description: scopeSelector is also a collection of filters like + scopes that must match each object tracked by a quota but expressed + using ScopeSelectorOperator in combination with possible values. + For a resource to match, both scopes AND scopeSelector (if specified + in spec), must be matched. + properties: + matchExpressions: + description: A list of scope selector requirements by scope + of the resources. + items: + description: A scoped-resource selector requirement is a + selector that contains values, a scope name, and an operator + that relates the scope name and values. + properties: + operator: + description: Represents a scope's relationship to a + set of values. Valid operators are In, NotIn, Exists, + DoesNotExist. + type: string + scopeName: + description: The name of the scope that the selector + applies to. + type: string + values: + description: An array of string values. If the operator + is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - operator + - scopeName + type: object + type: array + type: object + scopes: + description: A collection of filters that must match each object + tracked by a quota. If not specified, the quota matches all + objects. + items: + description: A ResourceQuotaScope defines a filter that must + match each object tracked by a quota + type: string + type: array + type: object + type: array + storageClasses: + items: + type: string + type: array + required: + - ingressClasses + - limitRanges + - namespaceQuota + - owner + - storageClasses + type: object + status: + description: TenantStatus defines the observed state of Tenant + properties: + groups: + items: + type: string + type: array + namespaces: + items: + type: string + type: array + size: + type: integer + users: + items: + type: string + type: array + required: + - size + type: object + type: object + version: v1alpha1 + versions: + - name: v1alpha1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml new file mode 100644 index 00000000..4ba94c12 --- /dev/null +++ b/config/crd/kustomization.yaml @@ -0,0 +1,10 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/capsule.clastix.io_tenants.yaml +# +kubebuilder:scaffold:crdkustomizeresource + +# the following config is for teaching kustomize how to do kustomization for CRDs. +configurations: +- kustomizeconfig.yaml diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml new file mode 100644 index 00000000..6f83d9a9 --- /dev/null +++ b/config/crd/kustomizeconfig.yaml @@ -0,0 +1,17 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + group: apiextensions.k8s.io + path: spec/conversion/webhookClientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + group: apiextensions.k8s.io + path: spec/conversion/webhookClientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml new file mode 100644 index 00000000..69a08ad3 --- /dev/null +++ b/config/default/kustomization.yaml @@ -0,0 +1,30 @@ +# Adds namespace to all resources. +namespace: capsule-system + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +# Note that it should also match with the prefix (text before '-') of the namespace +# field above. +namePrefix: capsule- + +# Labels to add to all resources and selectors. +#commonLabels: +# someName: someValue + +bases: +- ../crd +- ../rbac +- ../manager +- ../secret +- ../webhook +- ../tenants +# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. +#- ../prometheus + +patchesStrategicMerge: + # Protect the /metrics endpoint by putting it behind auth. + # If you want your controller-manager to expose the /metrics + # endpoint w/o any authn/z, please comment the following line. +- manager_auth_proxy_patch.yaml +- manager_webhook_patch.yaml diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 00000000..77e743d1 --- /dev/null +++ b/config/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,25 @@ +# This patch inject a sidecar container which is a HTTP proxy for the +# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=10" + ports: + - containerPort: 8443 + name: https + - name: manager + args: + - "--metrics-addr=127.0.0.1:8080" + - "--enable-leader-election" diff --git a/config/default/manager_webhook_patch.yaml b/config/default/manager_webhook_patch.yaml new file mode 100644 index 00000000..947e14e2 --- /dev/null +++ b/config/default/manager_webhook_patch.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: capsule-tls diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml new file mode 100644 index 00000000..af799cb4 --- /dev/null +++ b/config/manager/kustomization.yaml @@ -0,0 +1,8 @@ +resources: +- manager.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: quay.io/clastix/capsule + newTag: latest diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml new file mode 100644 index 00000000..d39b8b2b --- /dev/null +++ b/config/manager/manager.yaml @@ -0,0 +1,40 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + name: system +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system + labels: + control-plane: controller-manager +spec: + selector: + matchLabels: + control-plane: controller-manager + replicas: 1 + template: + metadata: + labels: + control-plane: controller-manager + spec: + containers: + - command: + - /manager + args: + - --enable-leader-election + image: quay.io/clastix/capsule:latest + imagePullPolicy: IfNotPresent + name: manager + resources: + limits: + cpu: 200m + memory: 128Mi + requests: + cpu: 200m + memory: 128Mi + terminationGracePeriodSeconds: 10 diff --git a/config/prometheus/kustomization.yaml b/config/prometheus/kustomization.yaml new file mode 100644 index 00000000..ed137168 --- /dev/null +++ b/config/prometheus/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- monitor.yaml diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml new file mode 100644 index 00000000..9b8047b7 --- /dev/null +++ b/config/prometheus/monitor.yaml @@ -0,0 +1,16 @@ + +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + name: controller-manager-metrics-monitor + namespace: system +spec: + endpoints: + - path: /metrics + port: https + selector: + matchLabels: + control-plane: controller-manager diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml new file mode 100644 index 00000000..7d62534c --- /dev/null +++ b/config/rbac/auth_proxy_client_clusterrole.yaml @@ -0,0 +1,7 @@ +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: metrics-reader +rules: +- nonResourceURLs: ["/metrics"] + verbs: ["get"] diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml new file mode 100644 index 00000000..618f5e41 --- /dev/null +++ b/config/rbac/auth_proxy_role.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: proxy-role +rules: +- apiGroups: ["authentication.k8s.io"] + resources: + - tokenreviews + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: + - subjectaccessreviews + verbs: ["create"] diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 00000000..48ed1e4b --- /dev/null +++ b/config/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: default + namespace: system diff --git a/config/rbac/auth_proxy_service.yaml b/config/rbac/auth_proxy_service.yaml new file mode 100644 index 00000000..6cf656be --- /dev/null +++ b/config/rbac/auth_proxy_service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + targetPort: https + selector: + control-plane: controller-manager diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml new file mode 100644 index 00000000..2f8909ba --- /dev/null +++ b/config/rbac/kustomization.yaml @@ -0,0 +1,9 @@ +resources: +- role_binding.yaml +# Comment the following 4 lines if you want to disable +# the auth proxy (https://github.com/brancz/kube-rbac-proxy) +# which protects your /metrics endpoint. +- auth_proxy_service.yaml +- auth_proxy_role.yaml +- auth_proxy_role_binding.yaml +- auth_proxy_client_clusterrole.yaml diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml new file mode 100644 index 00000000..1e2b98f9 --- /dev/null +++ b/config/rbac/role_binding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: manager-rolebinding +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: default + namespace: system diff --git a/deploy/crds/capsule.clastix.io_v1alpha1_tenant_cr.yaml b/config/samples/capsule_v1alpha1_tenant.yaml similarity index 100% rename from deploy/crds/capsule.clastix.io_v1alpha1_tenant_cr.yaml rename to config/samples/capsule_v1alpha1_tenant.yaml diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml new file mode 100644 index 00000000..b6cf0e17 --- /dev/null +++ b/config/samples/kustomization.yaml @@ -0,0 +1,3 @@ +## This file is auto-generated, do not modify ## +resources: +- capsule_v1alpha1_tenant.yaml diff --git a/config/secret/kustomization.yaml b/config/secret/kustomization.yaml new file mode 100644 index 00000000..a93504fd --- /dev/null +++ b/config/secret/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- secret-ca.yaml +- secret-tls.yaml diff --git a/config/secret/secret-ca.yaml b/config/secret/secret-ca.yaml new file mode 100644 index 00000000..b093850a --- /dev/null +++ b/config/secret/secret-ca.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Secret +metadata: + name: ca diff --git a/config/secret/secret-tls.yaml b/config/secret/secret-tls.yaml new file mode 100644 index 00000000..3e5e0fbb --- /dev/null +++ b/config/secret/secret-tls.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Secret +metadata: + name: tls diff --git a/config/tenants/kustomization.yaml b/config/tenants/kustomization.yaml new file mode 100644 index 00000000..594b2471 --- /dev/null +++ b/config/tenants/kustomization.yaml @@ -0,0 +1,3 @@ +resources: +- namespace-deleter.yaml +- namespace-provisioner.yaml diff --git a/deploy/namespace-deleter.yaml b/config/tenants/namespace-deleter.yaml similarity index 100% rename from deploy/namespace-deleter.yaml rename to config/tenants/namespace-deleter.yaml diff --git a/deploy/namespace-provisioner.yaml b/config/tenants/namespace-provisioner.yaml similarity index 100% rename from deploy/namespace-provisioner.yaml rename to config/tenants/namespace-provisioner.yaml diff --git a/config/webhook/kustomization.yaml b/config/webhook/kustomization.yaml new file mode 100644 index 00000000..9cf26134 --- /dev/null +++ b/config/webhook/kustomization.yaml @@ -0,0 +1,6 @@ +resources: +- manifests.yaml +- service.yaml + +configurations: +- kustomizeconfig.yaml diff --git a/config/webhook/kustomizeconfig.yaml b/config/webhook/kustomizeconfig.yaml new file mode 100644 index 00000000..25e21e3c --- /dev/null +++ b/config/webhook/kustomizeconfig.yaml @@ -0,0 +1,25 @@ +# the following config is for teaching kustomize where to look at when substituting vars. +# It requires kustomize v2.1.0 or newer to work properly. +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + - kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/name + +namespace: +- kind: MutatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true +- kind: ValidatingWebhookConfiguration + group: admissionregistration.k8s.io + path: webhooks/clientConfig/service/namespace + create: true + +varReference: +- path: metadata/annotations diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml new file mode 100644 index 00000000..286e88bb --- /dev/null +++ b/config/webhook/manifests.yaml @@ -0,0 +1,122 @@ + +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + creationTimestamp: null + name: mutating-webhook-configuration +webhooks: +- clientConfig: + caBundle: Cg== + service: + name: webhook-service + namespace: system + path: /mutate-v1-namespace-owner-reference + failurePolicy: Fail + name: owner.namespace.capsule.clastix.io + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - namespaces + +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: validating-webhook-configuration +webhooks: +- clientConfig: + caBundle: Cg== + service: + name: webhook-service + namespace: system + path: /validating-v1-extensions-ingress + failurePolicy: Fail + name: extensions.ingress.capsule.clastix.io + rules: + - apiGroups: + - extensions + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - ingresses +- clientConfig: + caBundle: Cg== + service: + name: webhook-service + namespace: system + path: /validating-v1-networking-ingress + failurePolicy: Fail + name: networking.ingress.capsule.clastix.io + rules: + - apiGroups: + - networking.k8s.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - ingresses +- clientConfig: + caBundle: Cg== + service: + name: webhook-service + namespace: system + path: /validate-v1-namespace-quota + failurePolicy: Fail + name: quota.namespace.capsule.clastix.io + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - namespaces +- clientConfig: + caBundle: Cg== + service: + name: webhook-service + namespace: system + path: /validating-v1-network-policy + failurePolicy: Fail + name: validating.network-policy.capsule.clastix.io + rules: + - apiGroups: + - networking.k8s.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - networkpolicies +- clientConfig: + caBundle: Cg== + service: + name: webhook-service + namespace: system + path: /validating-v1-pvc + failurePolicy: Fail + name: pvc.capsule.clastix.io + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - persistentvolumeclaims diff --git a/config/webhook/service.yaml b/config/webhook/service.yaml new file mode 100644 index 00000000..240b2016 --- /dev/null +++ b/config/webhook/service.yaml @@ -0,0 +1,11 @@ + +apiVersion: v1 +kind: Service +metadata: + name: webhook-service +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + control-plane: controller-manager diff --git a/contributing.md b/contributing.md index 7ca553f1..b7a09ba9 100644 --- a/contributing.md +++ b/contributing.md @@ -9,7 +9,8 @@ The first step is to setup your local development environment The following dependencies are mandatory: - [Go 1.13.8](https://golang.org/dl/) -- [OperatorSDK 1.8](https://github.com/operator-framework/operator-sdk) +- [OperatorSDK 1.9](https://github.com/operator-framework/operator-sdk) +- [Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) - [KinD](https://github.com/kubernetes-sigs/kind) - [ngrok](https://ngrok.com/) (if you want to run locally) - [golangci-lint](https://github.com/golangci/golangci-lint) @@ -29,6 +30,13 @@ Some operations, like the Docker image build process or the code-generation of the CRDs manifests, as well the deep copy functions, require _Operator SDK_: the binary has to be installed into your `PATH`. +### Installing Kubebuilder + +With the latest release of OperatorSDK there's a more tightly integration with +Kubebuilder and its opinionated testing suite: ensure to download the latest +binaries available from the _Releases_ GitHub page and place them into the +`/usr/local/kubebuilder/bin` folder, ensuring this is also in your `PATH`. + ### Installing KinD Capsule is able to run on any certified Kubernetes installation and locally @@ -68,37 +76,63 @@ certificates and the context changed to the just born Kubernetes cluster. From the root path, issue the _make_ recipe: ``` -# make docker-image -operator-sdk build quay.io/clastix/capsule:latest -INFO[0001] Building OCI image quay.io/clastix/capsule:latest -Sending build context to Docker daemon 89.26MB -Step 1/7 : FROM registry.access.redhat.com/ubi8/ubi-minimal:latest - ---> 75a64ccf990b -Step 2/7 : ENV OPERATOR=/usr/local/bin/capsule USER_UID=0 USER_NAME=capsule +# make docker-build +/home/prometherion/go/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..." +go fmt ./... +main.go +go vet ./... +/home/prometherion/go/bin/controller-gen "crd:trivialVersions=true" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases +go test ./... -coverprofile cover.out +... +docker build . -t quay.io/clastix/capsule:latest +Sending build context to Docker daemon 43.21MB +Step 1/15 : FROM golang:1.13 as builder + ---> 67d10cb69049 +Step 2/15 : WORKDIR /workspace ---> Using cache - ---> e4610bd8596f -Step 3/7 : COPY build/_output/bin/capsule ${OPERATOR} + ---> d783cc2b7c33 +Step 3/15 : COPY go.mod go.mod ---> Using cache - ---> 1f6196485c28 -Step 4/7 : COPY build/bin /usr/local/bin + ---> 0fec3ca39e50 +Step 4/15 : COPY go.sum go.sum ---> Using cache - ---> b517a62ca352 -Step 5/7 : RUN /usr/local/bin/user_setup + ---> de15be20dbe7 +Step 5/15 : RUN go mod download ---> Using cache - ---> e879394010d5 -Step 6/7 : ENTRYPOINT ["/usr/local/bin/entrypoint"] + ---> b525cd9abc67 +Step 6/15 : COPY main.go main.go + ---> 67d9d6538ffc +Step 7/15 : COPY api/ api/ + ---> 6243b250d170 +Step 8/15 : COPY controllers/ controllers/ + ---> 4abf8ce85484 +Step 9/15 : COPY pkg/ pkg/ + ---> 2cd289b1d496 +Step 10/15 : RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go + ---> Running in dac9a1e3b23f +Removing intermediate container dac9a1e3b23f + ---> bb650a8efcb2 +Step 11/15 : FROM gcr.io/distroless/static:nonroot + ---> 131713291b92 +Step 12/15 : WORKDIR / ---> Using cache - ---> 6e740290e0e4 -Step 7/7 : USER ${USER_UID} - ---> Using cache - ---> ebb8f640dda1 -Successfully built ebb8f640dda1 + ---> 677a73ab94d3 +Step 13/15 : COPY --from=builder /workspace/manager . + ---> 6ecb58a82c0a +Step 14/15 : USER nonroot:nonroot + ---> Running in a0b8c95f85d4 +Removing intermediate container a0b8c95f85d4 + ---> c4897d60a094 +Step 15/15 : ENTRYPOINT ["/manager"] + ---> Running in 1a42bab52aa7 +Removing intermediate container 1a42bab52aa7 + ---> 37d2adbe2669 +Successfully built 37d2adbe2669 Successfully tagged quay.io/clastix/capsule:latest -INFO[0004] Operator build complete. ``` The image `quay.io/clastix/capsule:latest` will be available locally, you just -need to push it to kind with the following command. +need to push it to _KinD_ with the following command. ``` # kind load docker-image --nodes capsule-control-plane --name capsule quay.io/clastix/capsule:latest @@ -107,45 +141,34 @@ Image: "quay.io/clastix/capsule:latest" with ID "sha256:ebb8f640dda129a795ddc68b ### Deploy the Kubernetes manifests -With the current `kind-capsule` context enabled, create the `capsule-system` -Namespace that will contain all the Kubernetes resources. +With the current `kind-capsule` context enabled, deploy all the required +manifests issuing the following command: ``` -# kubectl create namespace capsule-system -namespace/capsule-system created +make deploy ``` -Now it's time to install the _Custom Resource Definition_: +This will install all the required Kubernetes resources, automatically. + +You can check if Capsule is running tailing the logs: ``` -# kubectl apply -f deploy/crds/capsule.clastix.io_tenants_crd.yaml -customresourcedefinition.apiextensions.k8s.io/tenants.capsule.clastix.io created -``` - -Finally, install the required manifests issuing the following command: - -``` -# kubectl apply -f deploy -mutatingwebhookconfiguration.admissionregistration.k8s.io/capsule created -clusterrole.rbac.authorization.k8s.io/namespace:deleter created -clusterrole.rbac.authorization.k8s.io/namespace:provisioner created -clusterrolebinding.rbac.authorization.k8s.io/namespace:provisioner created -deployment.apps/capsule created -clusterrole.rbac.authorization.k8s.io/capsule created -clusterrolebinding.rbac.authorization.k8s.io/capsule-cluster-admin created -clusterrolebinding.rbac.authorization.k8s.io/capsule created -secret/capsule-ca created -secret/capsule-tls created -service/capsule created -serviceaccount/capsule created -``` - -You can check if Capsule is running checking the logs: - -``` -# kubectl -n capsule-system logs -f -l name=capsule +# kubectl -n capsule-system logs --all-containers -f -l control-plane=controller-manager ... -{"level":"info","ts":1596125071.5951712,"logger":"controller-runtime.controller","msg":"Starting workers","controller":"tenant-controller","worker count":1} +2020-08-03T15:37:44.031Z INFO controllers.Tenant Role Binding sync result: unchanged {"Request.Name": "oil", "name": "namespace:deleter", "namespace": "oil-dev"} +2020-08-03T15:37:44.032Z INFO controllers.Tenant Role Binding sync result: unchanged {"Request.Name": "oil", "name": "namespace:admin", "namespace": "oil-production"} +2020-08-03T15:37:44.032Z INFO controllers.Tenant Role Binding sync result: unchanged {"Request.Name": "oil", "name": "namespace:deleter", "namespace": "oil-production"} +2020-08-03T15:37:44.032Z INFO controllers.Tenant Tenant reconciling completed {"Request.Name": "oil"} +2020-08-03T15:37:44.032Z DEBUG controller-runtime.controller Successfully Reconciled {"controller": "tenant", "request": "/oil"} +2020-08-03T15:37:46.945Z INFO controllers.Namespace Reconciling Namespace {"Request.Name": "oil-staging"} +2020-08-03T15:37:46.953Z INFO controllers.Namespace Namespace reconciliation processed {"Request.Name": "oil-staging"} +2020-08-03T15:37:46.953Z DEBUG controller-runtime.controller Successfully Reconciled {"controller": "namespace", "request": "/oil-staging"} +2020-08-03T15:37:46.957Z INFO controllers.Namespace Reconciling Namespace {"Request.Name": "oil-staging"} +2020-08-03T15:37:46.957Z DEBUG controller-runtime.controller Successfully Reconciled {"controller": "namespace", "request": "/oil-staging"} +I0803 15:16:01.763606 1 main.go:186] Valid token audiences: +I0803 15:16:01.763689 1 main.go:232] Generating self signed cert as no cert is provided +I0803 15:16:02.042022 1 main.go:281] Starting TCP socket on 0.0.0.0:8443 +I0803 15:16:02.042364 1 main.go:288] Listening securely on 0.0.0.0:8443 ``` Since Capsule is built using _OperatorSDK_, logging is handled by the zap @@ -169,8 +192,8 @@ access to the Kubernetes API Server. First, ensure the Capsule pod is not running scaling down the Deployment. ``` -# kubectl -n capsule-system scale deployment capsule --replicas=0 -deployment.apps/capsule scaled +# kubectl -n capsule-system scale deployment capsule-controller-manager --replicas=0 +deployment.apps/capsule-controller-manager scaled ``` > This is mandatory since Capsule uses Leader Election @@ -197,7 +220,7 @@ In another session we need a `ngrok` session, mandatory to debug also webhooks (YMMV). ``` -# ngrok http localhost:443 +# ngrok http https://localhost:9443 ngrok by @inconshreveable Session Status online @@ -205,8 +228,8 @@ Account Dario Tranchitella (Plan: Free) Version 2.3.35 Region United States (us) Web Interface http://127.0.01:4040 -Forwarding http://cdb72b99348c.ngrok.io -> https://localhost:443 -Forwarding https://cdb72b99348c.ngrok.io -> https://localhost:443 +Forwarding http://cdb72b99348c.ngrok.io -> https://localhost:9443 +Forwarding https://cdb72b99348c.ngrok.io -> https://localhost:9443 Connections ttl opn rt1 rt5 p50 p90 0 0 0.00 0.00 0.00 0.00 ``` @@ -217,14 +240,15 @@ _Dynamic Admissions Control Webhooks_. #### Patching the MutatingWebhookConfiguration -Now it's time to patch the _MutatingWebhookConfiguration_, adding the said -`ngrok` URL as base for each defined webhook, as following: +Now it's time to patch the _MutatingWebhookConfiguration_ and the +_ValidatingWebhookConfiguration_ too, adding the said `ngrok` URL as base for +each defined webhook, as following: ```diff apiVersion: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration metadata: - name: capsule + name: capsule-mutating-webhook-configuration webhooks: - name: owner.namespace.capsule.clastix.io failurePolicy: Fail @@ -237,7 +261,7 @@ webhooks: + url: https://cdb72b99348c.ngrok.io/mutate-v1-namespace-owner-reference - caBundle: - service: -- namespace: capsule-system +- namespace: system - name: capsule - path: /mutate-v1-namespace-owner-reference ... @@ -249,7 +273,7 @@ Finally, it's time to run locally Capsule using your preferred IDE (or not): from the project root path you can issue the following command. ``` -WATCH_NAMESPACE= KUBECONFIG=/path/to/your/kubeconfig OPERATOR_NAME=capsule go run cmd/manager/main.go +make run ``` All the logs will start to flow in your standard output, feel free to attach diff --git a/pkg/controller/namespace/namespace_controller.go b/controllers/namespace_controller.go similarity index 52% rename from pkg/controller/namespace/namespace_controller.go rename to controllers/namespace_controller.go index fbc51eae..678d5478 100644 --- a/pkg/controller/namespace/namespace_controller.go +++ b/controllers/namespace_controller.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package namespace +package controllers import ( "context" @@ -24,106 +27,81 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" + "github.com/clastix/capsule/api/v1alpha1" ) -// Add creates a new Namespace Controller and adds it to the Manager. The Manager will set fields on the Controller -// and Start it when the Manager is Started. -func Add(mgr manager.Manager) error { - return add(mgr, newReconciler(mgr)) +type NamespaceReconciler struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme } -// newReconciler returns a new reconcile.Reconciler -func newReconciler(mgr manager.Manager) reconcile.Reconciler { - return &ReconcileNamespace{ - client: mgr.GetClient(), - scheme: mgr.GetScheme(), - } +func (r *NamespaceReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&corev1.Namespace{}, builder.WithPredicates(predicate.Funcs{ + CreateFunc: func(event event.CreateEvent) (ok bool) { + ok, _ = getCapsuleReference(event.Meta.GetOwnerReferences()) + return + }, + DeleteFunc: func(deleteEvent event.DeleteEvent) (ok bool) { + ok, _ = getCapsuleReference(deleteEvent.Meta.GetOwnerReferences()) + return + }, + UpdateFunc: func(updateEvent event.UpdateEvent) (ok bool) { + ok, _ = getCapsuleReference(updateEvent.MetaNew.GetOwnerReferences()) + return + }, + GenericFunc: func(genericEvent event.GenericEvent) (ok bool) { + ok, _ = getCapsuleReference(genericEvent.Meta.GetOwnerReferences()) + return + }, + })). + Complete(r) } func getCapsuleReference(refs []v1.OwnerReference) (ok bool, reference *v1.OwnerReference) { for _, r := range refs { - if r.APIVersion == v1alpha1.SchemeGroupVersion.String() { + if r.APIVersion == v1alpha1.GroupVersion.String() { return true, r.DeepCopy() } } return false, nil } -// add adds a new Controller to mgr with r as the reconcile.Reconciler -func add(mgr manager.Manager, r reconcile.Reconciler) error { - // Create a new controller - c, err := controller.New("namespace-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - - // Watch for changes to primary resource Namespace - err = c.Watch(&source.Kind{Type: &corev1.Namespace{}}, &handler.EnqueueRequestForObject{}, predicate.Funcs{ - CreateFunc: func(event event.CreateEvent) (ok bool) { - ok, _ = getCapsuleReference(event.Meta.GetOwnerReferences()) - return - }, - DeleteFunc: func(deleteEvent event.DeleteEvent) (ok bool) { - ok, _ = getCapsuleReference(deleteEvent.Meta.GetOwnerReferences()) - return - }, - UpdateFunc: func(updateEvent event.UpdateEvent) (ok bool) { - ok, _ = getCapsuleReference(updateEvent.MetaNew.GetOwnerReferences()) - return - }, - GenericFunc: func(genericEvent event.GenericEvent) (ok bool) { - ok, _ = getCapsuleReference(genericEvent.Meta.GetOwnerReferences()) - return - }, - }) - if err != nil { - return err - } - - return nil -} - -// ReconcileNamespace reconciles a Namespace object -type ReconcileNamespace struct { - client client.Client - scheme *runtime.Scheme - logger logr.Logger -} - -func (r *ReconcileNamespace) removeNamespace(name string, tenant *v1alpha1.Tenant) { +func (r *NamespaceReconciler) removeNamespace(name string, tenant *v1alpha1.Tenant) { c := tenant.Status.Namespaces.DeepCopy() sort.Sort(c) i := sort.SearchStrings(c, name) // namespace already removed, do nothing if i > c.Len() || i == c.Len() { + r.Log.Info("Namespace has been already removed") return } // namespace is there, removing it + r.Log.Info("Removing Namespace from Tenant status") tenant.Status.Namespaces = []string{} tenant.Status.Namespaces = append(tenant.Status.Namespaces, c[:i]...) tenant.Status.Namespaces = append(tenant.Status.Namespaces, c[i+1:]...) } -func (r *ReconcileNamespace) addNamespace(name string, tenant *v1alpha1.Tenant) { +func (r *NamespaceReconciler) addNamespace(name string, tenant *v1alpha1.Tenant) { c := tenant.Status.Namespaces.DeepCopy() sort.Sort(c) i := sort.SearchStrings(c, name) // namespace already there, nothing to do if i < c.Len() && c[i] == name { + r.Log.Info("Namespace has been already added") return } // missing namespace, let's append it + r.Log.Info("Adding Namespace to Tenant status") if i == 0 { tenant.Status.Namespaces = []string{name} } else { @@ -134,21 +112,20 @@ func (r *ReconcileNamespace) addNamespace(name string, tenant *v1alpha1.Tenant) tenant.Status.Namespaces = append(tenant.Status.Namespaces, c[i:]...) } -func (r *ReconcileNamespace) updateNamespaceCount(tenant *v1alpha1.Tenant) error { - tenant.Status.Size = uint(len(tenant.Status.Namespaces)) - +func (r *NamespaceReconciler) updateNamespaceCount(tenant *v1alpha1.Tenant) error { return retry.RetryOnConflict(retry.DefaultBackoff, func() error { - return r.client.Status().Update(context.TODO(), tenant, &client.UpdateOptions{}) + tenant.Status.Size = uint(len(tenant.Status.Namespaces)) + return r.Client.Status().Update(context.TODO(), tenant, &client.UpdateOptions{}) }) } -func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (res reconcile.Result, err error) { - r.logger = log.Log.WithName("controller_namespace").WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) - r.logger.Info("Reconciling Namespace") +func (r NamespaceReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) { + r.Log = r.Log.WithValues("Request.Name", request.Name) + r.Log.Info("Reconciling Namespace") // Fetch the Namespace instance ns := &corev1.Namespace{} - if err := r.client.Get(context.TODO(), request.NamespacedName, ns); err != nil { + if err := r.Get(context.TODO(), request.NamespacedName, ns); err != nil { if errors.IsNotFound(err) { // Request object not found, could have been deleted after reconcile request. // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. @@ -161,27 +138,27 @@ func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (res reconcile _, or := getCapsuleReference(ns.OwnerReferences) t := &v1alpha1.Tenant{} - if err := r.client.Get(context.TODO(), types.NamespacedName{Name: or.Name}, t); err != nil { + if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: or.Name}, t); err != nil { // Error reading the object - requeue the request. return reconcile.Result{}, err } if err := r.ensureLabel(ns, t.Name); err != nil { - r.logger.Error(err, "cannot update Namespace label") + r.Log.Error(err, "cannot update Namespace label") return reconcile.Result{}, err } r.updateTenantStatus(ns, t) if err := r.updateNamespaceCount(t); err != nil { - r.logger.Error(err, "cannot update Namespace list", "tenant", t.Name) + r.Log.Error(err, "cannot update Namespace list", "tenant", t.Name) } - r.logger.Info("Namespace reconciliation processed") + r.Log.Info("Namespace reconciliation processed") return reconcile.Result{}, nil } -func (r *ReconcileNamespace) ensureLabel(ns *corev1.Namespace, tenantName string) error { +func (r *NamespaceReconciler) ensureLabel(ns *corev1.Namespace, tenantName string) error { capsuleLabel, err := v1alpha1.GetTypeLabel(&v1alpha1.Tenant{}) if err != nil { return err @@ -191,15 +168,15 @@ func (r *ReconcileNamespace) ensureLabel(ns *corev1.Namespace, tenantName string } tl, ok := ns.Labels[capsuleLabel] if !ok || tl != tenantName { - ns.Labels[capsuleLabel] = tenantName return retry.RetryOnConflict(retry.DefaultBackoff, func() error { - return r.client.Update(context.TODO(), ns, &client.UpdateOptions{}) + ns.Labels[capsuleLabel] = tenantName + return r.Client.Update(context.TODO(), ns, &client.UpdateOptions{}) }) } return nil } -func (r *ReconcileNamespace) updateTenantStatus(ns *corev1.Namespace, tenant *v1alpha1.Tenant) { +func (r *NamespaceReconciler) updateTenantStatus(ns *corev1.Namespace, tenant *v1alpha1.Tenant) { switch ns.Status.Phase { case corev1.NamespaceTerminating: r.removeNamespace(ns.Name, tenant) diff --git a/controllers/secret/ca.go b/controllers/secret/ca.go new file mode 100644 index 00000000..48b27cd3 --- /dev/null +++ b/controllers/secret/ca.go @@ -0,0 +1,177 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package secret + +import ( + "bytes" + "context" + "errors" + "time" + + "github.com/go-logr/logr" + v1 "k8s.io/api/admissionregistration/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/clastix/capsule/pkg/cert" +) + +type CaReconciler struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme +} + +func (r *CaReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&corev1.Secret{}, forOptionPerInstanceName(caSecretName)). + Complete(r) +} + +func (r CaReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) { + var err error + + r.Log = log.Log.WithName("controller_ca").WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + r.Log.Info("Reconciling CA Secret") + + // Fetch the CA instance + instance := &corev1.Secret{} + err = r.Client.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + var ca cert.Ca + var rq time.Duration + ca, err = getCertificateAuthority(r.Client) + if err != nil && errors.Is(err, MissingCaError{}) { + ca, err = cert.GenerateCertificateAuthority() + if err != nil { + return reconcile.Result{}, err + } + } else if err != nil { + return reconcile.Result{}, err + } + + r.Log.Info("Handling CA Secret") + + rq, err = ca.ExpiresIn(time.Now()) + if err != nil { + r.Log.Info("CA is expired, cleaning to obtain a new one") + instance.Data = map[string][]byte{} + } else { + r.Log.Info("Updating CA secret with new PEM and RSA") + + var crt *bytes.Buffer + var key *bytes.Buffer + crt, _ = ca.CaCertificatePem() + key, _ = ca.CaPrivateKeyPem() + + instance.Data = map[string][]byte{ + certSecretKey: crt.Bytes(), + privateKeySecretKey: key.Bytes(), + } + // Updating ValidatingWebhookConfiguration CA bundle + err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + vw := &v1.ValidatingWebhookConfiguration{} + err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-validating-webhook-configuration"}, vw) + if err != nil { + r.Log.Error(err, "cannot retrieve ValidatingWebhookConfiguration") + return err + } + for i, w := range vw.Webhooks { + // Updating CABundle only in case of an internal service reference + if w.ClientConfig.Service != nil { + vw.Webhooks[i].ClientConfig.CABundle = instance.Data[certSecretKey] + } + } + err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + return r.Update(context.TODO(), vw, &client.UpdateOptions{}) + }) + if err != nil { + r.Log.Error(err, "cannot update MutatingWebhookConfiguration webhooks CA bundle") + return err + } + return r.Update(context.TODO(), vw, &client.UpdateOptions{}) + }) + // Updating MutatingWebhookConfiguration CA bundle + err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + mw := &v1.MutatingWebhookConfiguration{} + err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-mutating-webhook-configuration"}, mw) + if err != nil { + r.Log.Error(err, "cannot retrieve MutatingWebhookConfiguration") + return err + } + for i, w := range mw.Webhooks { + // Updating CABundle only in case of an internal service reference + if w.ClientConfig.Service != nil { + mw.Webhooks[i].ClientConfig.CABundle = instance.Data[certSecretKey] + } + } + return r.Update(context.TODO(), mw, &client.UpdateOptions{}) + }) + if err != nil { + r.Log.Error(err, "cannot update MutatingWebhookConfiguration webhooks CA bundle") + return reconcile.Result{}, err + } + } + + var res controllerutil.OperationResult + t := &corev1.Secret{ObjectMeta: instance.ObjectMeta} + res, err = controllerutil.CreateOrUpdate(context.TODO(), r.Client, t, func() error { + t.Data = instance.Data + return nil + }) + if err != nil { + r.Log.Error(err, "cannot update Capsule TLS") + return reconcile.Result{}, err + } + + if res == controllerutil.OperationResultUpdated { + r.Log.Info("Capsule CA has been updated, we need to trigger TLS update too") + tls := &corev1.Secret{} + err = r.Get(context.TODO(), types.NamespacedName{ + Namespace: "capsule-system", + Name: tlsSecretName, + }, tls) + if err != nil { + r.Log.Error(err, "Capsule TLS Secret missing") + } + err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + _, err = controllerutil.CreateOrUpdate(context.TODO(), r.Client, tls, func() error { + tls.Data = map[string][]byte{} + return nil + }) + return err + }) + if err != nil { + r.Log.Error(err, "Cannot clean Capsule TLS Secret due to CA update") + return reconcile.Result{}, err + } + } + + r.Log.Info("Reconciliation completed, processing back in " + rq.String()) + return reconcile.Result{Requeue: true, RequeueAfter: rq}, nil +} diff --git a/pkg/controller/secret/const.go b/controllers/secret/const.go similarity index 81% rename from pkg/controller/secret/const.go rename to controllers/secret/const.go index 2bfc4238..35a6b394 100644 --- a/pkg/controller/secret/const.go +++ b/controllers/secret/const.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,9 +17,9 @@ limitations under the License. package secret const ( - Cert = "tls.crt" - PrivateKey = "tls.key" + certSecretKey = "tls.crt" + privateKeySecretKey = "tls.key" - CaSecretName = "capsule-ca" - TlsSecretName = "capsule-tls" + caSecretName = "capsule-ca" + tlsSecretName = "capsule-tls" ) diff --git a/pkg/webhook/add_pvc.go b/controllers/secret/errors.go similarity index 79% rename from pkg/webhook/add_pvc.go rename to controllers/secret/errors.go index 7bffca2c..7bfb58e4 100644 --- a/pkg/webhook/add_pvc.go +++ b/controllers/secret/errors.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,12 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -package webhook +package secret -import ( - "github.com/clastix/capsule/pkg/webhook/pvc" -) - -func init() { - AddToWebhookServer = append(AddToWebhookServer, pvc.Add) +type MissingCaError struct { +} + +func (MissingCaError) Error() string { + return "CA has not been created yet, please generate a new" } diff --git a/controllers/secret/reconciler.go b/controllers/secret/reconciler.go new file mode 100644 index 00000000..5024ed7a --- /dev/null +++ b/controllers/secret/reconciler.go @@ -0,0 +1,75 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package secret + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + + "github.com/clastix/capsule/pkg/cert" +) + +func getCertificateAuthority(client client.Client) (ca cert.Ca, err error) { + instance := &corev1.Secret{} + + err = client.Get(context.TODO(), types.NamespacedName{ + Namespace: "capsule-system", + Name: caSecretName, + }, instance) + if err != nil { + return nil, fmt.Errorf("missing secret %s, cannot reconcile", caSecretName) + } + + if instance.Data == nil { + return nil, MissingCaError{} + } + + ca, err = cert.NewCertificateAuthorityFromBytes(instance.Data[certSecretKey], instance.Data[privateKeySecretKey]) + if err != nil { + return + } + + return +} + +func forOptionPerInstanceName(instanceName string) builder.ForOption { + return builder.WithPredicates(predicate.Funcs{ + CreateFunc: func(event event.CreateEvent) bool { + return filterByName(event.Meta.GetName(), instanceName) + }, + DeleteFunc: func(deleteEvent event.DeleteEvent) bool { + return filterByName(deleteEvent.Meta.GetName(), instanceName) + }, + UpdateFunc: func(updateEvent event.UpdateEvent) bool { + return filterByName(updateEvent.MetaNew.GetName(), instanceName) + }, + GenericFunc: func(genericEvent event.GenericEvent) bool { + return filterByName(genericEvent.Meta.GetName(), instanceName) + }, + }) +} + +func filterByName(objName, desired string) bool { + return objName == desired +} diff --git a/controllers/secret/tls.go b/controllers/secret/tls.go new file mode 100644 index 00000000..32092ced --- /dev/null +++ b/controllers/secret/tls.go @@ -0,0 +1,127 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package secret + +import ( + "context" + "crypto/x509" + "encoding/pem" + "syscall" + "time" + + "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/clastix/capsule/pkg/cert" +) + +type TlsReconciler struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme +} + +func (r *TlsReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&corev1.Secret{}, forOptionPerInstanceName(tlsSecretName)). + Complete(r) +} + +func (r TlsReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) { + var err error + + r.Log = r.Log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + r.Log.Info("Reconciling TLS Secret") + + // Fetch the Secret instance + instance := &corev1.Secret{} + err = r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + var ca cert.Ca + var rq time.Duration + + ca, err = getCertificateAuthority(r.Client) + if err != nil { + return reconcile.Result{}, err + } + + var shouldCreate bool + for _, key := range []string{certSecretKey, privateKeySecretKey} { + if _, ok := instance.Data[key]; !ok { + shouldCreate = true + } + } + + if shouldCreate { + r.Log.Info("Missing Capsule TLS certificate") + rq = 6 * 30 * 24 * time.Hour + + opts := cert.NewCertOpts(time.Now().Add(rq), "capsule-webhook-service.capsule-system.svc") + crt, key, err := ca.GenerateCertificate(opts) + if err != nil { + r.Log.Error(err, "Cannot generate new TLS certificate") + return reconcile.Result{}, err + } + instance.Data = map[string][]byte{ + certSecretKey: crt.Bytes(), + privateKeySecretKey: key.Bytes(), + } + } else { + var c *x509.Certificate + var b *pem.Block + b, _ = pem.Decode(instance.Data[certSecretKey]) + c, err = x509.ParseCertificate(b.Bytes) + if err != nil { + r.Log.Error(err, "cannot parse Capsule TLS") + return reconcile.Result{}, err + } + + rq = time.Duration(c.NotAfter.Unix()-time.Now().Unix()) * time.Second + if time.Now().After(c.NotAfter) { + r.Log.Info("Capsule TLS is expired, cleaning to obtain a new one") + instance.Data = map[string][]byte{} + } + } + + var res controllerutil.OperationResult + t := &corev1.Secret{ObjectMeta: instance.ObjectMeta} + res, err = controllerutil.CreateOrUpdate(context.TODO(), r.Client, t, func() error { + t.Data = instance.Data + return nil + }) + if err != nil { + r.Log.Error(err, "cannot update Capsule TLS") + return reconcile.Result{}, err + } + + if instance.Name == tlsSecretName && res == controllerutil.OperationResultUpdated { + r.Log.Info("Capsule TLS certificates has been updated, we need to restart the Controller") + _ = syscall.Kill(syscall.Getpid(), syscall.SIGINT) + } + + r.Log.Info("Reconciliation completed, processing back in " + rq.String()) + return reconcile.Result{Requeue: true, RequeueAfter: rq}, nil +} diff --git a/controllers/suite_test.go b/controllers/suite_test.go new file mode 100644 index 00000000..467ff35d --- /dev/null +++ b/controllers/suite_test.go @@ -0,0 +1,81 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + capsulev1alpha "github.com/clastix/capsule/api/v1alpha1" + // +kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecsWithDefaultAndCustomReporters(t, + "Controller Suite", + []Reporter{printer.NewlineReporter{}}) +} + +var _ = BeforeSuite(func(done Done) { + logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, + } + + var err error + cfg, err = testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + err = capsulev1alpha.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + // +kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).ToNot(HaveOccurred()) + Expect(k8sClient).ToNot(BeNil()) + + close(done) +}, 60) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) diff --git a/pkg/controller/tenant/tenant_controller.go b/controllers/tenant_controller.go similarity index 68% rename from pkg/controller/tenant/tenant_controller.go rename to controllers/tenant_controller.go index 838101be..3f4e7fdc 100644 --- a/pkg/controller/tenant/tenant_controller.go +++ b/controllers/tenant_controller.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tenant +package controllers import ( "context" @@ -32,119 +35,83 @@ import ( "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" + ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - capsulev1alpha1 "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" + capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1" ) -// Add creates a new Tenant Controller and adds it to the Manager. The Manager will set fields on the Controller -// and Start it when the Manager is Started. -func Add(mgr manager.Manager) error { - return add(mgr, &ReconcileTenant{ - client: mgr.GetClient(), - scheme: mgr.GetScheme(), - logger: log.Log.WithName("controller_tenant"), - }) +// TenantReconciler reconciles a Tenant object +type TenantReconciler struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme } -// add adds a new Controller to mgr with r as the reconcile.Reconciler -func add(mgr manager.Manager, r reconcile.Reconciler) error { - // Create a new controller - c, err := controller.New("tenant-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - - // Watch for changes to primary resource Tenant - err = c.Watch(&source.Kind{Type: &capsulev1alpha1.Tenant{}}, &handler.EnqueueRequestForObject{}) - if err != nil { - return err - } - - // Watch for controlled resources - for _, r := range []runtime.Object{&networkingv1.NetworkPolicy{}, &corev1.LimitRange{}, &corev1.ResourceQuota{}, &rbacv1.RoleBinding{}} { - err = c.Watch(&source.Kind{Type: r}, &handler.EnqueueRequestForOwner{ - IsController: true, - OwnerType: &capsulev1alpha1.Tenant{}, - }) - if err != nil { - return err - } - } - - return nil +func (r *TenantReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&capsulev1alpha1.Tenant{}). + Owns(&networkingv1.NetworkPolicy{}). + Owns(&corev1.LimitRange{}). + Owns(&corev1.ResourceQuota{}). + Owns(&rbacv1.RoleBinding{}). + Complete(r) } -// ReconcileTenant reconciles a Tenant object -type ReconcileTenant struct { - client client.Client - scheme *runtime.Scheme - logger logr.Logger -} - -// Reconcile reads that state of the cluster for a Tenant object and makes changes based on the state read -// and what is in the Tenant.Spec -// The Controller will requeue the Request to be processed again if the returned error is non-nil or -// Result.Requeue is true, otherwise upon completion it will remove the work from the queue. -func (r *ReconcileTenant) Reconcile(request reconcile.Request) (reconcile.Result, error) { - r.logger = log.Log.WithName("controller_tenant").WithValues("Request.Name", request.Name) +func (r TenantReconciler) Reconcile(request ctrl.Request) (ctrl.Result, error) { + r.Log = r.Log.WithValues("Request.Name", request.Name) // Fetch the Tenant instance instance := &capsulev1alpha1.Tenant{} - err := r.client.Get(context.TODO(), request.NamespacedName, instance) + err := r.Get(context.TODO(), request.NamespacedName, instance) if err != nil { if errors.IsNotFound(err) { - r.logger.Info("Request object not found, could have been deleted after reconcile request") + r.Log.Info("Request object not found, could have been deleted after reconcile request") return reconcile.Result{}, nil } - r.logger.Error(err, "Error reading the object") + r.Log.Error(err, "Error reading the object") return reconcile.Result{}, err } - r.logger.Info("Starting processing of Network Policies", "items", len(instance.Spec.NetworkPolicies)) + r.Log.Info("Starting processing of Network Policies", "items", len(instance.Spec.NetworkPolicies)) if err := r.syncNetworkPolicies(instance); err != nil { - r.logger.Error(err, "Cannot sync NetworkPolicy items") + r.Log.Error(err, "Cannot sync NetworkPolicy items") return reconcile.Result{}, err } - r.logger.Info("Starting processing of Node Selector") + r.Log.Info("Starting processing of Node Selector") if err := r.ensureNodeSelector(instance); err != nil { - r.logger.Error(err, "Cannot sync Namespaces Node Selector items") + r.Log.Error(err, "Cannot sync Namespaces Node Selector items") return reconcile.Result{}, err } - r.logger.Info("Starting processing of Limit Ranges", "items", len(instance.Spec.LimitRanges)) + r.Log.Info("Starting processing of Limit Ranges", "items", len(instance.Spec.LimitRanges)) if err := r.syncLimitRanges(instance); err != nil { - r.logger.Error(err, "Cannot sync LimitRange items") + r.Log.Error(err, "Cannot sync LimitRange items") return reconcile.Result{}, err } - r.logger.Info("Starting processing of Resource Quotas", "items", len(instance.Spec.ResourceQuota)) + r.Log.Info("Starting processing of Resource Quotas", "items", len(instance.Spec.ResourceQuota)) if err := r.syncResourceQuotas(instance); err != nil { - r.logger.Error(err, "Cannot sync ResourceQuota items") + r.Log.Error(err, "Cannot sync ResourceQuota items") return reconcile.Result{}, err } - r.logger.Info("Ensuring RoleBinding for owner") + r.Log.Info("Ensuring RoleBinding for owner") if err := r.ownerRoleBinding(instance); err != nil { - r.logger.Error(err, "Cannot sync owner RoleBinding") + r.Log.Error(err, "Cannot sync owner RoleBinding") return reconcile.Result{}, err } - r.logger.Info("Tenant reconciling completed") - return reconcile.Result{}, nil + r.Log.Info("Tenant reconciling completed") + return ctrl.Result{}, nil } // pruningResources is taking care of removing the no more requested sub-resources as LimitRange, ResourceQuota or // NetworkPolicy using the "notin" LabelSelector to perform an outer-join removal. -func (r *ReconcileTenant) pruningResources(ns string, keys []string, obj runtime.Object) error { +func (r *TenantReconciler) pruningResources(ns string, keys []string, obj runtime.Object) error { capsuleLabel, err := capsulev1alpha1.GetTypeLabel(obj) if err != nil { return err @@ -153,9 +120,9 @@ func (r *ReconcileTenant) pruningResources(ns string, keys []string, obj runtime if err != nil { return err } - r.logger.Info("Pruning objects with label selector " + req.String()) + r.Log.Info("Pruning objects with label selector " + req.String()) err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - return r.client.DeleteAllOf(context.TODO(), obj, &client.DeleteAllOfOptions{ + return r.DeleteAllOf(context.TODO(), obj, &client.DeleteAllOfOptions{ ListOptions: client.ListOptions{ LabelSelector: labels.NewSelector().Add(*req), Namespace: ns, @@ -173,7 +140,7 @@ func (r *ReconcileTenant) pruningResources(ns string, keys []string, obj runtime // Serial ResourceQuota processing is expensive: using Go routines we can speed it up. // In case of multiple errors these are logged properly, returning a generic error since we have to repush back the // reconciliation loop. -func (r *ReconcileTenant) resourceQuotasUpdate(resourceName corev1.ResourceName, qt resource.Quantity, list ...corev1.ResourceQuota) (err error) { +func (r *TenantReconciler) resourceQuotasUpdate(resourceName corev1.ResourceName, qt resource.Quantity, list ...corev1.ResourceQuota) (err error) { ch := make(chan error, len(list)) wg := &sync.WaitGroup{} @@ -184,7 +151,7 @@ func (r *ReconcileTenant) resourceQuotasUpdate(resourceName corev1.ResourceName, ch <- retry.RetryOnConflict(retry.DefaultBackoff, func() error { // Retrieving from the cache the actual ResourceQuota found := &corev1.ResourceQuota{} - _ = r.client.Get(context.TODO(), types.NamespacedName{Namespace: rq.Namespace, Name: rq.Name}, found) + _ = r.Get(context.TODO(), types.NamespacedName{Namespace: rq.Namespace, Name: rq.Name}, found) // Ensuring annotation map is there to avoid uninitialized map error and // assigning the overall usage if found.Annotations == nil { @@ -194,7 +161,7 @@ func (r *ReconcileTenant) resourceQuotasUpdate(resourceName corev1.ResourceName, found.Annotations[capsulev1alpha1.UsedQuotaFor(resourceName)] = qt.String() // Updating the Resource according to the qt.Cmp result found.Spec.Hard = rq.Spec.Hard - return r.client.Update(context.TODO(), found, &client.UpdateOptions{}) + return r.Update(context.TODO(), found, &client.UpdateOptions{}) }) } @@ -209,7 +176,7 @@ func (r *ReconcileTenant) resourceQuotasUpdate(resourceName corev1.ResourceName, // We had an error and we mark the whole transaction as failed // to process it another time acording to the Tenant controller back-off factor. err = fmt.Errorf("update of outer ResourceQuota items has failed") - r.logger.Error(err, "Cannot update outer ResourceQuotas", "resourceName", resourceName.String()) + r.Log.Error(err, "Cannot update outer ResourceQuotas", "resourceName", resourceName.String()) } } return @@ -223,7 +190,7 @@ func (r *ReconcileTenant) resourceQuotasUpdate(resourceName corev1.ResourceName, // .Status.Used value as the .Hard value. // This will trigger a following reconciliation but that's ok: the mutateFn will re-use the same business logic, letting // the mutateFn along with the CreateOrUpdate to don't perform the update since resources are identical. -func (r *ReconcileTenant) syncResourceQuotas(tenant *capsulev1alpha1.Tenant) error { +func (r *TenantReconciler) syncResourceQuotas(tenant *capsulev1alpha1.Tenant) error { // getting requested ResourceQuota keys keys := make([]string, 0, len(tenant.Spec.ResourceQuota)) for i := range tenant.Spec.ResourceQuota { @@ -256,27 +223,27 @@ func (r *ReconcileTenant) syncResourceQuotas(tenant *capsulev1alpha1.Tenant) err }, }, } - res, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, target, func() (err error) { + res, err := controllerutil.CreateOrUpdate(context.TODO(), r.Client, target, func() (err error) { // Requirement to list ResourceQuota of the current Tenant tr, err := labels.NewRequirement(tenantLabel, selection.Equals, []string{tenant.Name}) if err != nil { - r.logger.Error(err, "Cannot build ResourceQuota Tenant requirement") + r.Log.Error(err, "Cannot build ResourceQuota Tenant requirement") } // Requirement to list ResourceQuota for the current index ir, err := labels.NewRequirement(typeLabel, selection.Equals, []string{strconv.Itoa(i)}) if err != nil { - r.logger.Error(err, "Cannot build ResourceQuota index requirement") + r.Log.Error(err, "Cannot build ResourceQuota index requirement") } // Listing all the ResourceQuota according to the said requirements. // These are required since Capsule is going to sum all the used quota to // sum them and get the Tenant one. rql := &corev1.ResourceQuotaList{} - err = r.client.List(context.TODO(), rql, &client.ListOptions{ + err = r.List(context.TODO(), rql, &client.ListOptions{ LabelSelector: labels.NewSelector().Add(*tr).Add(*ir), }) if err != nil { - r.logger.Error(err, "Cannot list ResourceQuota", "tenantFilter", tr.String(), "indexFilter", ir.String()) + r.Log.Error(err, "Cannot list ResourceQuota", "tenantFilter", tr.String(), "indexFilter", ir.String()) return err } @@ -286,14 +253,14 @@ func (r *ReconcileTenant) syncResourceQuotas(tenant *capsulev1alpha1.Tenant) err // For this case, we're going to block the Quota setting the Hard as the // used one. for rn, rq := range q.Hard { - r.logger.Info("Desired hard " + rn.String() + " quota is " + rq.String()) + r.Log.Info("Desired hard " + rn.String() + " quota is " + rq.String()) // Getting the whole usage across all the Tenant Namespaces var qt resource.Quantity for _, rq := range rql.Items { qt.Add(rq.Status.Used[rn]) } - r.logger.Info("Computed " + rn.String() + " quota for the whole Tenant is " + qt.String()) + r.Log.Info("Computed " + rn.String() + " quota for the whole Tenant is " + qt.String()) switch qt.Cmp(q.Hard[rn]) { case 0: @@ -324,13 +291,13 @@ func (r *ReconcileTenant) syncResourceQuotas(tenant *capsulev1alpha1.Tenant) err target.Spec = q } if err := r.resourceQuotasUpdate(rn, qt, rql.Items...); err != nil { - r.logger.Error(err, "cannot proceed with outer ResourceQuota") + r.Log.Error(err, "cannot proceed with outer ResourceQuota") return err } } - return controllerutil.SetControllerReference(tenant, target, r.scheme) + return controllerutil.SetControllerReference(tenant, target, r.Scheme) }) - r.logger.Info("Resource Quota sync result: "+string(res), "name", target.Name, "namespace", target.Namespace) + r.Log.Info("Resource Quota sync result: "+string(res), "name", target.Name, "namespace", target.Namespace) if err != nil { return err } @@ -341,7 +308,7 @@ func (r *ReconcileTenant) syncResourceQuotas(tenant *capsulev1alpha1.Tenant) err } // Ensuring all the LimitRange are applied to each Namespace handled by the Tenant. -func (r *ReconcileTenant) syncLimitRanges(tenant *capsulev1alpha1.Tenant) error { +func (r *TenantReconciler) syncLimitRanges(tenant *capsulev1alpha1.Tenant) error { // getting requested LimitRange keys keys := make([]string, 0, len(tenant.Spec.LimitRanges)) for i := range tenant.Spec.LimitRanges { @@ -369,15 +336,15 @@ func (r *ReconcileTenant) syncLimitRanges(tenant *capsulev1alpha1.Tenant) error Namespace: ns, }, } - res, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, t, func() (err error) { + res, err := controllerutil.CreateOrUpdate(context.TODO(), r.Client, t, func() (err error) { t.ObjectMeta.Labels = map[string]string{ tl: tenant.Name, ll: strconv.Itoa(i), } t.Spec = spec - return controllerutil.SetControllerReference(tenant, t, r.scheme) + return controllerutil.SetControllerReference(tenant, t, r.Scheme) }) - r.logger.Info("LimitRange sync result: "+string(res), "name", t.Name, "namespace", t.Namespace) + r.Log.Info("LimitRange sync result: "+string(res), "name", t.Name, "namespace", t.Namespace) if err != nil { return err } @@ -388,7 +355,7 @@ func (r *ReconcileTenant) syncLimitRanges(tenant *capsulev1alpha1.Tenant) error } // Ensuring all the NetworkPolicies are applied to each Namespace handled by the Tenant. -func (r *ReconcileTenant) syncNetworkPolicies(tenant *capsulev1alpha1.Tenant) error { +func (r *TenantReconciler) syncNetworkPolicies(tenant *capsulev1alpha1.Tenant) error { // getting requested NetworkPolicy keys keys := make([]string, 0, len(tenant.Spec.NetworkPolicies)) for i := range tenant.Spec.NetworkPolicies { @@ -420,11 +387,11 @@ func (r *ReconcileTenant) syncNetworkPolicies(tenant *capsulev1alpha1.Tenant) er }, }, } - res, err := controllerutil.CreateOrUpdate(context.TODO(), r.client, t, func() (err error) { + res, err := controllerutil.CreateOrUpdate(context.TODO(), r.Client, t, func() (err error) { t.Spec = spec - return controllerutil.SetControllerReference(tenant, t, r.scheme) + return controllerutil.SetControllerReference(tenant, t, r.Scheme) }) - r.logger.Info("Network Policy sync result: "+string(res), "name", t.Name, "namespace", t.Namespace) + r.Log.Info("Network Policy sync result: "+string(res), "name", t.Name, "namespace", t.Namespace) if err != nil { return err } @@ -438,7 +405,7 @@ func (r *ReconcileTenant) syncNetworkPolicies(tenant *capsulev1alpha1.Tenant) er // Since RBAC is based on deny all first, some specific actions like editing Capsule resources are going to be blocked // via Dynamic Admission Webhooks. // TODO(prometherion): we could create a capsule:admin role rather than hitting webhooks for each action -func (r *ReconcileTenant) ownerRoleBinding(tenant *capsulev1alpha1.Tenant) error { +func (r *TenantReconciler) ownerRoleBinding(tenant *capsulev1alpha1.Tenant) error { // getting RoleBinding label for the mutateFn tl, err := capsulev1alpha1.GetTypeLabel(&capsulev1alpha1.Tenant{}) if err != nil { @@ -463,7 +430,7 @@ func (r *ReconcileTenant) ownerRoleBinding(tenant *capsulev1alpha1.Tenant) error rbl[types.NamespacedName{Namespace: i, Name: "namespace:deleter"}] = rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", - Name: "namespace:deleter", + Name: "capsule-namespace:deleter", } } @@ -476,13 +443,13 @@ func (r *ReconcileTenant) ownerRoleBinding(tenant *capsulev1alpha1.Tenant) error } var res controllerutil.OperationResult - res, err = controllerutil.CreateOrUpdate(context.TODO(), r.client, target, func() (err error) { + res, err = controllerutil.CreateOrUpdate(context.TODO(), r.Client, target, func() (err error) { target.ObjectMeta.Labels = l target.Subjects = s target.RoleRef = rr - return controllerutil.SetControllerReference(tenant, target, r.scheme) + return controllerutil.SetControllerReference(tenant, target, r.Scheme) }) - r.logger.Info("Role Binding sync result: "+string(res), "name", target.Name, "namespace", target.Namespace) + r.Log.Info("Role Binding sync result: "+string(res), "name", target.Name, "namespace", target.Namespace) if err != nil { return err } @@ -490,7 +457,7 @@ func (r *ReconcileTenant) ownerRoleBinding(tenant *capsulev1alpha1.Tenant) error return nil } -func (r *ReconcileTenant) ensureNodeSelector(tenant *capsulev1alpha1.Tenant) (err error) { +func (r *TenantReconciler) ensureNodeSelector(tenant *capsulev1alpha1.Tenant) (err error) { if tenant.Spec.NodeSelector == nil { return } @@ -508,7 +475,7 @@ func (r *ReconcileTenant) ensureNodeSelector(tenant *capsulev1alpha1.Tenant) (er } var res controllerutil.OperationResult - res, err = controllerutil.CreateOrUpdate(context.TODO(), r.client, ns, func() error { + res, err = controllerutil.CreateOrUpdate(context.TODO(), r.Client, ns, func() error { if ns.Annotations == nil { ns.Annotations = make(map[string]string) } @@ -519,7 +486,7 @@ func (r *ReconcileTenant) ensureNodeSelector(tenant *capsulev1alpha1.Tenant) (er ns.Annotations["scheduler.alpha.kubernetes.io/node-selector"] = strings.Join(selector, ",") return nil }) - r.logger.Info("Namespace Node sync result: "+string(res), "name", ns.Name) + r.Log.Info("Namespace Node sync result: "+string(res), "name", ns.Name) if err != nil { return err } diff --git a/deploy/crds/capsule.clastix.io_tenants_crd.yaml b/deploy/crds/capsule.clastix.io_tenants_crd.yaml deleted file mode 100644 index 56bb6a25..00000000 --- a/deploy/crds/capsule.clastix.io_tenants_crd.yaml +++ /dev/null @@ -1,710 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: tenants.capsule.clastix.io -spec: - group: capsule.clastix.io - names: - kind: Tenant - listKind: TenantList - plural: tenants - singular: tenant - scope: Cluster - versions: - - additionalPrinterColumns: - - description: The max amount of Namespaces can be created - jsonPath: .spec.namespaceQuota - name: Namespace quota - type: integer - - description: The total amount of Namespaces in use - jsonPath: .status.size - name: Namespace count - type: integer - name: v1alpha1 - schema: - openAPIV3Schema: - description: Tenant is the Schema for the tenants API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: TenantSpec defines the desired state of Tenant - properties: - ingressClasses: - items: - type: string - type: array - limitRanges: - items: - description: LimitRangeSpec defines a min/max usage limit for resources - that match on kind. - properties: - limits: - description: Limits is the list of LimitRangeItem objects that - are enforced. - items: - description: LimitRangeItem defines a min/max usage limit - for any resource that matches on kind. - properties: - default: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Default resource requirement limit value - by resource name if resource limit is omitted. - type: object - defaultRequest: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: DefaultRequest is the default resource requirement - request value by resource name if resource request is - omitted. - type: object - max: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Max usage constraints on this kind by resource - name. - type: object - maxLimitRequestRatio: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: MaxLimitRequestRatio if specified, the named - resource must have a request and limit that are both - non-zero where limit divided by request is less than - or equal to the enumerated value; this represents the - max burst for the named resource. - type: object - min: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: Min usage constraints on this kind by resource - name. - type: object - type: - description: Type of resource that this limit applies - to. - type: string - required: - - type - type: object - type: array - required: - - limits - type: object - type: array - namespaceQuota: - minimum: 1 - type: integer - networkPolicies: - items: - description: NetworkPolicySpec provides the specification of a NetworkPolicy - properties: - egress: - description: List of egress rules to be applied to the selected - pods. Outgoing traffic is allowed if there are no NetworkPolicies - selecting the pod (and cluster policy otherwise allows the - traffic), OR if the traffic matches at least one egress rule - across all of the NetworkPolicy objects whose podSelector - matches the pod. If this field is empty then this NetworkPolicy - limits all outgoing traffic (and serves solely to ensure that - the pods it selects are isolated by default). This field is - beta-level in 1.8 - items: - description: NetworkPolicyEgressRule describes a particular - set of traffic that is allowed out of pods matched by a - NetworkPolicySpec's podSelector. The traffic must match - both ports and to. This type is beta-level in 1.8 - properties: - ports: - description: List of destination ports for outgoing traffic. - Each item in this list is combined using a logical OR. - If this field is empty or missing, this rule matches - all ports (traffic not restricted by port). If this - field is present and contains at least one item, then - this rule allows traffic only if the traffic matches - at least one port in the list. - items: - description: NetworkPolicyPort describes a port to allow - traffic on - properties: - port: - anyOf: - - type: integer - - type: string - description: The port on the given protocol. This - can either be a numerical or named port on a pod. - If this field is not provided, this matches all - port names and numbers. - x-kubernetes-int-or-string: true - protocol: - description: The protocol (TCP, UDP, or SCTP) which - traffic must match. If not specified, this field - defaults to TCP. - type: string - type: object - type: array - to: - description: List of destinations for outgoing traffic - of pods selected for this rule. Items in this list are - combined using a logical OR operation. If this field - is empty or missing, this rule matches all destinations - (traffic not restricted by destination). If this field - is present and contains at least one item, this rule - allows traffic only if the traffic matches at least - one item in the to list. - items: - description: NetworkPolicyPeer describes a peer to allow - traffic from. Only certain combinations of fields - are allowed - properties: - ipBlock: - description: IPBlock defines policy on a particular - IPBlock. If this field is set then neither of - the other fields can be. - properties: - cidr: - description: CIDR is a string representing the - IP Block Valid examples are "192.168.1.1/24" - or "2001:db9::/64" - type: string - except: - description: Except is a slice of CIDRs that - should not be included within an IP Block - Valid examples are "192.168.1.1/24" or "2001:db9::/64" - Except values will be rejected if they are - outside the CIDR range - items: - type: string - type: array - required: - - cidr - type: object - namespaceSelector: - description: "Selects Namespaces using cluster-scoped - labels. This field follows standard label selector - semantics; if present but empty, it selects all - namespaces. \n If PodSelector is also set, then - the NetworkPolicyPeer as a whole selects the Pods - matching PodSelector in the Namespaces selected - by NamespaceSelector. Otherwise it selects all - Pods in the Namespaces selected by NamespaceSelector." - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. - type: object - type: object - podSelector: - description: "This is a label selector which selects - Pods. This field follows standard label selector - semantics; if present but empty, it selects all - pods. \n If NamespaceSelector is also set, then - the NetworkPolicyPeer as a whole selects the Pods - matching PodSelector in the Namespaces selected - by NamespaceSelector. Otherwise it selects the - Pods matching PodSelector in the policy's own - Namespace." - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. - type: object - type: object - type: object - type: array - type: object - type: array - ingress: - description: List of ingress rules to be applied to the selected - pods. Traffic is allowed to a pod if there are no NetworkPolicies - selecting the pod (and cluster policy otherwise allows the - traffic), OR if the traffic source is the pod's local node, - OR if the traffic matches at least one ingress rule across - all of the NetworkPolicy objects whose podSelector matches - the pod. If this field is empty then this NetworkPolicy does - not allow any traffic (and serves solely to ensure that the - pods it selects are isolated by default) - items: - description: NetworkPolicyIngressRule describes a particular - set of traffic that is allowed to the pods matched by a - NetworkPolicySpec's podSelector. The traffic must match - both ports and from. - properties: - from: - description: List of sources which should be able to access - the pods selected for this rule. Items in this list - are combined using a logical OR operation. If this field - is empty or missing, this rule matches all sources (traffic - not restricted by source). If this field is present - and contains at least one item, this rule allows traffic - only if the traffic matches at least one item in the - from list. - items: - description: NetworkPolicyPeer describes a peer to allow - traffic from. Only certain combinations of fields - are allowed - properties: - ipBlock: - description: IPBlock defines policy on a particular - IPBlock. If this field is set then neither of - the other fields can be. - properties: - cidr: - description: CIDR is a string representing the - IP Block Valid examples are "192.168.1.1/24" - or "2001:db9::/64" - type: string - except: - description: Except is a slice of CIDRs that - should not be included within an IP Block - Valid examples are "192.168.1.1/24" or "2001:db9::/64" - Except values will be rejected if they are - outside the CIDR range - items: - type: string - type: array - required: - - cidr - type: object - namespaceSelector: - description: "Selects Namespaces using cluster-scoped - labels. This field follows standard label selector - semantics; if present but empty, it selects all - namespaces. \n If PodSelector is also set, then - the NetworkPolicyPeer as a whole selects the Pods - matching PodSelector in the Namespaces selected - by NamespaceSelector. Otherwise it selects all - Pods in the Namespaces selected by NamespaceSelector." - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. - type: object - type: object - podSelector: - description: "This is a label selector which selects - Pods. This field follows standard label selector - semantics; if present but empty, it selects all - pods. \n If NamespaceSelector is also set, then - the NetworkPolicyPeer as a whole selects the Pods - matching PodSelector in the Namespaces selected - by NamespaceSelector. Otherwise it selects the - Pods matching PodSelector in the policy's own - Namespace." - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. - type: object - type: object - type: object - type: array - ports: - description: List of ports which should be made accessible - on the pods selected for this rule. Each item in this - list is combined using a logical OR. If this field is - empty or missing, this rule matches all ports (traffic - not restricted by port). If this field is present and - contains at least one item, then this rule allows traffic - only if the traffic matches at least one port in the - list. - items: - description: NetworkPolicyPort describes a port to allow - traffic on - properties: - port: - anyOf: - - type: integer - - type: string - description: The port on the given protocol. This - can either be a numerical or named port on a pod. - If this field is not provided, this matches all - port names and numbers. - x-kubernetes-int-or-string: true - protocol: - description: The protocol (TCP, UDP, or SCTP) which - traffic must match. If not specified, this field - defaults to TCP. - type: string - type: object - type: array - type: object - type: array - podSelector: - description: Selects the pods to which this NetworkPolicy object - applies. The array of ingress rules is applied to any pods - selected by this field. Multiple network policies can select - the same set of pods. In this case, the ingress rules for - each are combined additively. This field is NOT optional and - follows standard label selector semantics. An empty podSelector - matches all pods in this namespace. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - policyTypes: - description: List of rule types that the NetworkPolicy relates - to. Valid options are "Ingress", "Egress", or "Ingress,Egress". - If this field is not specified, it will default based on the - existence of Ingress or Egress rules; policies that contain - an Egress section are assumed to affect Egress, and all policies - (whether or not they contain an Ingress section) are assumed - to affect Ingress. If you want to write an egress-only policy, - you must explicitly specify policyTypes [ "Egress" ]. Likewise, - if you want to write a policy that specifies that no egress - is allowed, you must specify a policyTypes value that include - "Egress" (since such a policy would not include an Egress - section and would otherwise default to just [ "Ingress" ]). - This field is beta-level in 1.8 - items: - description: Policy Type string describes the NetworkPolicy - type This type is beta-level in 1.8 - type: string - type: array - required: - - podSelector - type: object - type: array - nodeSelector: - additionalProperties: - type: string - type: object - owner: - type: string - resourceQuotas: - items: - description: ResourceQuotaSpec defines the desired hard limits to - enforce for Quota. - properties: - hard: - additionalProperties: - anyOf: - - type: integer - - type: string - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - description: 'hard is the set of desired hard limits for each - named resource. More info: https://kubernetes.io/docs/concepts/policy/resource-quotas/' - type: object - scopeSelector: - description: scopeSelector is also a collection of filters like - scopes that must match each object tracked by a quota but - expressed using ScopeSelectorOperator in combination with - possible values. For a resource to match, both scopes AND - scopeSelector (if specified in spec), must be matched. - properties: - matchExpressions: - description: A list of scope selector requirements by scope - of the resources. - items: - description: A scoped-resource selector requirement is - a selector that contains values, a scope name, and an - operator that relates the scope name and values. - properties: - operator: - description: Represents a scope's relationship to - a set of values. Valid operators are In, NotIn, - Exists, DoesNotExist. - type: string - scopeName: - description: The name of the scope that the selector - applies to. - type: string - values: - description: An array of string values. If the operator - is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during - a strategic merge patch. - items: - type: string - type: array - required: - - operator - - scopeName - type: object - type: array - type: object - scopes: - description: A collection of filters that must match each object - tracked by a quota. If not specified, the quota matches all - objects. - items: - description: A ResourceQuotaScope defines a filter that must - match each object tracked by a quota - type: string - type: array - type: object - type: array - storageClasses: - items: - type: string - type: array - required: - - ingressClasses - - limitRanges - - namespaceQuota - - owner - - storageClasses - type: object - status: - description: TenantStatus defines the observed state of Tenant - properties: - groups: - items: - type: string - type: array - namespaces: - items: - type: string - type: array - size: - type: integer - users: - items: - type: string - type: array - required: - - size - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/deploy/mutatingwebhookconfiguration.yaml b/deploy/mutatingwebhookconfiguration.yaml deleted file mode 100644 index 74d0e4c7..00000000 --- a/deploy/mutatingwebhookconfiguration.yaml +++ /dev/null @@ -1,96 +0,0 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: MutatingWebhookConfiguration -metadata: - name: capsule -webhooks: - - name: owner.namespace.capsule.clastix.io - failurePolicy: Fail - rules: - - apiGroups: [""] - apiVersions: ["v1"] - operations: ["CREATE"] - resources: ["namespaces"] - clientConfig: - # use url if you're developing locally - # url: https://.ngrok.io/mutate-v1-namespace-owner-reference - caBundle: - service: - namespace: capsule-system - name: capsule - path: /mutate-v1-namespace-owner-reference - - name: quota.namespace.capsule.clastix.io - failurePolicy: Fail - rules: - - apiGroups: [""] - apiVersions: ["v1"] - operations: ["CREATE"] - resources: ["namespaces"] - clientConfig: - # use url if you're developing locally - # url: https://.ngrok.io/validate-v1-namespace-quota - caBundle: - service: - namespace: capsule-system - name: capsule - path: /validate-v1-namespace-quota - - name: validating.network-policy.capsule.clastix.io - failurePolicy: Fail - rules: - - apiGroups: ["networking.k8s.io"] - apiVersions: ["v1"] - operations: ["CREATE", "UPDATE", "DELETE"] - resources: ["networkpolicies"] - clientConfig: - # use url if you're developing locally - # url: https://.ngrok.io/validating-v1-network-policy - caBundle: - service: - namespace: capsule-system - name: capsule - path: /validating-v1-network-policy - - name: pvc.capsule.clastix.io - failurePolicy: Fail - rules: - - apiGroups: [""] - apiVersions: ["v1"] - operations: ["CREATE"] - resources: ["persistentvolumeclaims"] - clientConfig: - # use url if you're developing locally - # url: https://.ngrok.io/validating-v1-pvc - caBundle: - service: - namespace: capsule-system - name: capsule - path: /validating-v1-pvc - - name: extensions.ingress.capsule.clastix.io - failurePolicy: Fail - rules: - - apiGroups: ["extensions"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE"] - resources: ["ingresses"] - clientConfig: - # use url if you're developing locally - # url: https://.ngrok.io/validating-v1-extensions-ingress - caBundle: - service: - namespace: capsule-system - name: capsule - path: /validating-v1-extensions-ingress - - - name: networking.ingress.capsule.clastix.io - failurePolicy: Fail - rules: - - apiGroups: ["networking.k8s.io"] - apiVersions: ["v1beta1"] - operations: ["CREATE", "UPDATE"] - resources: ["ingresses"] - clientConfig: - # use url if you're developing locally - # url: https://.ngrok.io/validating-v1-networking-ingress - caBundle: - service: - namespace: capsule-system - name: capsule - path: /validating-v1-networking-ingress \ No newline at end of file diff --git a/deploy/operator.yaml b/deploy/operator.yaml deleted file mode 100644 index 5a65feee..00000000 --- a/deploy/operator.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: capsule - namespace: capsule-system -spec: - replicas: 1 - selector: - matchLabels: - name: capsule - template: - metadata: - labels: - name: capsule - spec: - serviceAccountName: capsule - containers: - - name: capsule - image: quay.io/clastix/capsule:latest - command: - - capsule - imagePullPolicy: IfNotPresent - env: - - name: WATCH_NAMESPACE - value: "" - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: OPERATOR_NAME - value: "capsule" - volumeMounts: - - name: tls - mountPath: /tmp/k8s-webhook-server/serving-certs - volumes: - - name: tls - secret: - secretName: capsule-tls \ No newline at end of file diff --git a/deploy/role.yaml b/deploy/role.yaml deleted file mode 100644 index 9b11797a..00000000 --- a/deploy/role.yaml +++ /dev/null @@ -1,44 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - name: capsule -rules: -- apiGroups: - - admissionregistration.k8s.io - resources: - - mutatingwebhookconfigurations - verbs: - - get - - list - - watch - - update - - patch -- apiGroups: - - "" - resources: - - limitranges - - resourcequotas - - namespaces - - secrets - verbs: - - create - - delete - - deletecollection - - get - - list - - patch - - update - - watch -- apiGroups: - - capsule.clastix.io - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch diff --git a/deploy/role_binding.yaml b/deploy/role_binding.yaml deleted file mode 100644 index b8407438..00000000 --- a/deploy/role_binding.yaml +++ /dev/null @@ -1,25 +0,0 @@ -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: capsule-cluster-admin -subjects: -- kind: ServiceAccount - name: capsule - namespace: capsule-system -roleRef: - kind: ClusterRole - name: admin - apiGroup: rbac.authorization.k8s.io ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: capsule -subjects: - - kind: ServiceAccount - name: capsule - namespace: capsule-system -roleRef: - kind: ClusterRole - name: capsule - apiGroup: rbac.authorization.k8s.io diff --git a/deploy/secret-ca.yaml b/deploy/secret-ca.yaml deleted file mode 100644 index 41a5dc14..00000000 --- a/deploy/secret-ca.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - labels: - app: capsule - name: capsule-ca - namespace: capsule-system \ No newline at end of file diff --git a/deploy/secret-tls.yaml b/deploy/secret-tls.yaml deleted file mode 100644 index 82586149..00000000 --- a/deploy/secret-tls.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - labels: - app: capsule - name: capsule-tls - namespace: capsule-system \ No newline at end of file diff --git a/deploy/service.yaml b/deploy/service.yaml deleted file mode 100644 index 4ebb3f00..00000000 --- a/deploy/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: capsule - name: capsule - namespace: capsule-system -spec: - ports: - - name: https - port: 443 - protocol: TCP - targetPort: 443 - selector: - name: capsule - type: ClusterIP diff --git a/deploy/service_account.yaml b/deploy/service_account.yaml deleted file mode 100644 index 19747c12..00000000 --- a/deploy/service_account.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: capsule - namespace: capsule-system \ No newline at end of file diff --git a/go.mod b/go.mod index d2352a57..0104678c 100644 --- a/go.mod +++ b/go.mod @@ -4,16 +4,11 @@ go 1.13 require ( github.com/go-logr/logr v0.1.0 - github.com/operator-framework/operator-sdk v0.18.1 - github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.5.1 + github.com/onsi/ginkgo v1.11.0 + github.com/onsi/gomega v1.8.1 + github.com/stretchr/testify v1.4.0 k8s.io/api v0.18.2 k8s.io/apimachinery v0.18.2 - k8s.io/client-go v12.0.0+incompatible + k8s.io/client-go v0.18.2 sigs.k8s.io/controller-runtime v0.6.0 ) - -replace ( - github.com/Azure/go-autorest => github.com/Azure/go-autorest v13.3.2+incompatible // Required by OLM - k8s.io/client-go => k8s.io/client-go v0.18.2 // Required by prometheus-operator -) diff --git a/go.sum b/go.sum index 74202a1a..89e74abf 100644 --- a/go.sum +++ b/go.sum @@ -1,154 +1,38 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= +cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.49.0 h1:CH+lkubJzcPYB1Ggupcq0+k8Ni2ILdG2lYjDIgavDBQ= -cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.3.0/go.mod h1:9IAwXhoyBJ7z9LcAwkj0/7NnPzYaPeZxxVp3zm+5IqA= -contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest v13.3.2+incompatible h1:VxzPyuhtnlBOzc4IWCZHqpyH2d+QMLQEuy3wREyY4oc= -github.com/Azure/go-autorest v13.3.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.9.3-0.20191028180845-3492b2aff503 h1:uUhdsDMg2GbFLF5GfQPtLMWd5vdDZSfqvqQp3waafxQ= -github.com/Azure/go-autorest/autorest v0.9.3-0.20191028180845-3492b2aff503/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503 h1:Hxqlh1uAA8aGpa1dFhDNhll7U/rkWtG8ZItFvRMr7l0= -github.com/Azure/go-autorest/autorest/adal v0.8.1-0.20191028180845-3492b2aff503/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/autorest/to v0.3.1-0.20191028180845-3492b2aff503/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= -github.com/Azure/go-autorest/autorest/validation v0.2.1-0.20191028180845-3492b2aff503/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= -github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.1.0/go.mod h1:ONGMf7UfYGAbMXCZmQLy8x3lCDIPrEZE/rU8pmrbihA= -github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= -github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= -github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= -github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= -github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= -github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= -github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/brancz/gojsontoyaml v0.0.0-20191212081931-bf2969bbd742/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0= -github.com/brancz/kube-rbac-proxy v0.5.0/go.mod h1:cL2VjiIFGS90Cjh5ZZ8+It6tMcBt8rwvuw2J6Mamnl0= -github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= -github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= -github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= -github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= -github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= -github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -157,344 +41,145 @@ github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc h1:nMbUjGuF7UzVluucix/vsy4973BNdEiT/aX6kFtskKM= -github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc/go.mod h1:erio69w1R/aC14D5nfvAXSlE8FT8jt2Hnavc50Dp33A= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= -github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= -github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4/go.mod h1:+bmmJDNmKlhWNG+gwWCkaBoTy39Fs+bzRxVBzoTQbIc= -github.com/cznic/internal v0.0.0-20180608152220-f44710a21d00/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4= -github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A= -github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= -github.com/cznic/ql v1.2.0/go.mod h1:FbpzhyZrqr0PVlK6ury+PoW3T0ODUV22OeWIxcaOrSE= -github.com/cznic/sortutil v0.0.0-20150617083342-4c7342852e65/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ= -github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= -github.com/cznic/zappy v0.0.0-20160723133515-2533cb5b45cc/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= -github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= -github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= -github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190103212154-2b7e084dc98b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v0.7.3-0.20190817195342-4760db040282/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyzzjiW90t8cY= -github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= -github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= -github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.1.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= -github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= -github.com/go-logr/zapr v0.1.1 h1:qXBXPDdNncunGs7XeEpsJt8wCjYBygluzfdLO0G5baE= -github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhteGfloI10GD4U= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= -github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= -github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= -github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= -github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang-migrate/migrate/v4 v4.6.2/go.mod h1:JYi6reN3+Z734VZ0akNuyOJNcrg45ZL7LDBMW3WGJL0= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE= -github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= -github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= -github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.2.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.6.0 h1:Xb2lcqZtml1XjgYZxbeayEemq7ASbeTp09m36gQFpEU= -github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= -github.com/grpc-ecosystem/grpc-health-probe v0.2.1-0.20181220223928-2bf0a5b182db/go.mod h1:uBKkC2RbarFsvS5jMJHpVhTLvGlGQj9JJwkaePE3FWI= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.1.5/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jsonnet-bundler/jsonnet-bundler v0.3.1/go.mod h1:/by7P/OoohkI3q4CgSFqcoFsVY+IaNbzOVDknEsKDeU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -502,20 +187,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= -github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= -github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -523,406 +194,133 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= -github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU= -github.com/mikefarah/yq/v2 v2.4.1/go.mod h1:i8SYf1XdgUvY2OFwSqGAtWOOgimD2McJ6iutoxRm4k0= -github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE= -github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= -github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v0.0.0-20170117200651-66bb6560562f/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/openshift/origin v0.0.0-20160503220234-8f127d736703/go.mod h1:0Rox5r9C8aQn6j1oAOQ0c1uC86mYbUFObzjBRvUKHII= -github.com/openshift/prom-label-proxy v0.1.1-0.20191016113035-b8153a7f39f1/go.mod h1:p5MuxzsYP1JPsNGwtjtcgRHHlGziCJJfztff91nNixw= -github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q= -github.com/operator-framework/operator-registry v1.12.6-0.20200605115407-01fa069730e2/go.mod h1:loVINznYhgBIkmv83kU4yee88RS0BBk+hqOw9r4bhJk= -github.com/operator-framework/operator-sdk v0.18.1 h1:AOUOBchkx8r3yYF/MDjH0gdtd13ACENuy2gnsSXQXt0= -github.com/operator-framework/operator-sdk v0.18.1/go.mod h1:QMFHXj8+SxF56tfR1QmIU/tc9FKI73TG8Qw7Iy4D2zY= -github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE= -github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg= -github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.2.0/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= -github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U= -github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= -github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= -github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI= -github.com/prometheus/prometheus v2.3.2+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= -github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/vfsgen v0.0.0-20180825020608-02ddb050ef6b/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc= -github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/uber/jaeger-client-go v2.20.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= -github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= -github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= -github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= -go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk= -go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY= -go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE= -go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU= -go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= -go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -932,302 +330,112 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190425145619-16072639606e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= -golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190918214516-5a1a30219888/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191111182352-50fa39b762bc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b h1:AFZdJUT7jJYXQEC29hYH/WZkoV7+KhwxQGmdZ19yYoY= -golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= -gomodules.xyz/jsonpatch/v3 v3.0.1/go.mod h1:CBhndykehEwTOlEfnsfJwvkFQbSN8YZFr9M+cIHAJto= -gomodules.xyz/orderedmap v0.1.0/go.mod h1:g9/TPUCm1t2gwD3j3zfV8uylyYhVdCNSi+xCEIu7yTU= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= -google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= -gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.1.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -helm.sh/helm/v3 v3.2.0/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A= -k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= -k8s.io/api v0.0.0-20191115095533-47f6de673b26/go.mod h1:iA/8arsvelvo4IDqIhX4IbjTEKBGgvsf2OraTuRtLFU= -k8s.io/api v0.0.0-20191122220107-b5267f2975e0/go.mod h1:vYpRfxYkMrmPPSesoHEkGNHxNKTk96REAwqm/inQbs0= -k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= k8s.io/api v0.18.2 h1:wG5g5ZmSVgm5B+eHMIbI9EGATS2L8Z72rda19RIEgY8= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY= -k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo= k8s.io/apiextensions-apiserver v0.18.2 h1:I4v3/jAuQC+89L3Z7dDgAiN4EOjN6sbm6iBqQwHTah8= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= -k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA= -k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= -k8s.io/apimachinery v0.0.0-20191115015347-3c7067801da2/go.mod h1:dXFS2zaQR8fyzuvRdJDHw2Aerij/yVGJSre0bZQSVJA= -k8s.io/apimachinery v0.0.0-20191121175448-79c2a76c473a/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.2 h1:44CmtbmkzVDAhCpRVSiP2R5PPrC2RtlIv/MoB8xpdRA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg= -k8s.io/apiserver v0.0.0-20191122221311-9d521947b1e1/go.mod h1:RbsZY5zzBIWnz4KbctZsTVjwIuOpTp4Z8oCgFHN4kZQ= -k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= -k8s.io/autoscaler v0.0.0-20190607113959-1b4f1855cb8e/go.mod h1:QEXezc9uKPT91dwqhSJq3GNI3B1HxFRQHiku9kmrsSA= -k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ= -k8s.io/cli-runtime v0.18.2/go.mod h1:yfFR2sQQzDsV0VEKGZtrJwEy4hLZ2oj4ZIfodgxAHWQ= k8s.io/client-go v0.18.2 h1:aLB0iaD4nmwh7arT2wIn+lMnAq7OswjaejkQ8p9bBYE= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= -k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= -k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA= -k8s.io/component-base v0.0.0-20191122220729-2684fb322cb9/go.mod h1:NFuUusy/X4Tk21m21tcNUihnmp4OI7lXU7/xA+rYXkc= -k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20190320154901-5e45bb682580/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-state-metrics v1.7.2 h1:6vdtgXrrRRMSgnyDmgua+qvgCYv954JNfxXAtDkeLVQ= -k8s.io/kube-state-metrics v1.7.2/go.mod h1:U2Y6DRi07sS85rmVPmBFlmv+2peBcL8IWGjM+IjYA/E= -k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= -k8s.io/kubectl v0.18.2/go.mod h1:OdgFa3AlsPKRpFFYE7ICTwulXOcMGXHTc+UKhHKvrb4= -k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8= -k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4= -k8s.io/metrics v0.18.2/go.mod h1:qga8E7QfYNR9Q89cSCAjinC9pTZ7yv1XSVGUB0vJypg= -k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvOk9NM= sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo= -sigs.k8s.io/controller-tools v0.2.4/go.mod h1:m/ztfQNocGYBgTTCmFdnK94uVvgxeZeE3LtJvd/jIzA= -sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= -sigs.k8s.io/kubebuilder v1.0.9-0.20200513134826-f07a0146a40b/go.mod h1:FGPx0hvP73+bapzWoy5ePuhAJYgJjrFbPxgvWyortM0= -sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/hack/.gitignore b/hack/.gitignore deleted file mode 100644 index 30791b79..00000000 --- a/hack/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.kubeconfig \ No newline at end of file diff --git a/pkg/webhook/add_owner_reference.go b/hack/boilerplate.go.txt similarity index 76% rename from pkg/webhook/add_owner_reference.go rename to hack/boilerplate.go.txt index f0a15f73..12baadbf 100644 --- a/pkg/webhook/add_owner_reference.go +++ b/hack/boilerplate.go.txt @@ -1,20 +1,15 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -*/ - -package webhook - -import "github.com/clastix/capsule/pkg/webhook/owner_reference" - -func init() { - AddToWebhookServer = append(AddToWebhookServer, owner_reference.Add) -} +*/ \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 00000000..edc95ac2 --- /dev/null +++ b/main.go @@ -0,0 +1,149 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "flag" + "fmt" + "os" + goRuntime "runtime" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1" + "github.com/clastix/capsule/controllers" + "github.com/clastix/capsule/controllers/secret" + "github.com/clastix/capsule/pkg/indexer" + "github.com/clastix/capsule/pkg/webhook" + "github.com/clastix/capsule/pkg/webhook/ingress" + "github.com/clastix/capsule/pkg/webhook/namespace_quota" + "github.com/clastix/capsule/pkg/webhook/network_policies" + "github.com/clastix/capsule/pkg/webhook/owner_reference" + "github.com/clastix/capsule/pkg/webhook/pvc" + "github.com/clastix/capsule/version" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(capsulev1alpha1.AddToScheme(scheme)) + utilruntime.Must(corev1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func printVersion() { + setupLog.Info(fmt.Sprintf("Operator Version: %s", version.Version)) + setupLog.Info(fmt.Sprintf("Go Version: %s", goRuntime.Version())) + setupLog.Info(fmt.Sprintf("Go OS/Arch: %s/%s", goRuntime.GOOS, goRuntime.GOARCH)) +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var v bool + flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") + flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&v, "version", false, "Print the Capsule version and exit") + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseDevMode(true))) + + printVersion() + if v { + os.Exit(0) + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Port: 9443, + LeaderElection: enableLeaderElection, + LeaderElectionID: "42c733ea.clastix.capsule.io", + }) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + if err = (&controllers.TenantReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("Tenant"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Tenant") + os.Exit(1) + } + // +kubebuilder:scaffold:builder + + //webhooks + err = webhook.Register(mgr, &ingress.ExtensionIngress{}, &ingress.NetworkIngress{}, pvc.Webhook{}, &owner_reference.Webhook{}, &namespace_quota.Webhook{}, network_policies.Webhook{}) + if err != nil { + setupLog.Error(err, "unable to setup webhooks") + os.Exit(1) + } + + if err = (&controllers.NamespaceReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("Namespace"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Namespace") + os.Exit(1) + } + + if err = (&secret.CaReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("CA"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Namespace") + os.Exit(1) + } + if err = (&secret.TlsReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("Tls"), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Namespace") + os.Exit(1) + } + + if err := indexer.AddToManager(mgr); err != nil { + setupLog.Error(err, "unable to setup indexers") + os.Exit(1) + } + + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/pkg/apis/addtoscheme_capsule_v1alpha1.go b/pkg/apis/addtoscheme_capsule_v1alpha1.go deleted file mode 100644 index 680cd652..00000000 --- a/pkg/apis/addtoscheme_capsule_v1alpha1.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package apis - -import ( - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" -) - -func init() { - // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back - AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) -} diff --git a/pkg/apis/capsule/group.go b/pkg/apis/capsule/group.go deleted file mode 100644 index 660d4810..00000000 --- a/pkg/apis/capsule/group.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package capsule contains capsule API versions. -// -// This file ensures Go source parsers acknowledge the capsule package -// and any child packages. It can be removed if any other Go source files are -// added to this package. -package capsule diff --git a/pkg/apis/capsule/v1alpha1/doc.go b/pkg/apis/capsule/v1alpha1/doc.go deleted file mode 100644 index 8eca46e8..00000000 --- a/pkg/apis/capsule/v1alpha1/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package v1alpha1 contains API Schema definitions for the capsule v1alpha1 API group -// +k8s:deepcopy-gen=package,register -// +groupName=capsule.clastix.io -package v1alpha1 diff --git a/pkg/cert/ca.go b/pkg/cert/ca.go index 1320500f..6d0e0ee9 100644 --- a/pkg/cert/ca.go +++ b/pkg/cert/ca.go @@ -1,3 +1,19 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package cert import ( diff --git a/pkg/cert/ca_test.go b/pkg/cert/ca_test.go index 496be1ee..1f7bd00a 100644 --- a/pkg/cert/ca_test.go +++ b/pkg/cert/ca_test.go @@ -36,7 +36,7 @@ func TestCapsuleCa_GenerateCertificate(t *testing.T) { } for name, c := range map[string]testCase{ "foo.tld": {[]string{"foo.tld"}}, - "SAN": {[]string{"capsule.capsule-system.svc", "capsule.capsule-system.default.cluster"}}, + "SAN": {[]string{"capsule-webhook-service.capsule-system.svc", "capsule-webhook-service.capsule-system.default.cluster"}}, } { t.Run(name, func(t *testing.T) { var ca *CapsuleCa diff --git a/pkg/cert/errors.go b/pkg/cert/errors.go index 795ebaac..c46468dd 100644 --- a/pkg/cert/errors.go +++ b/pkg/cert/errors.go @@ -1,3 +1,19 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package cert type CaNotYetValidError struct{} diff --git a/pkg/cert/options.go b/pkg/cert/options.go index 0d9f2b7c..1a61a498 100644 --- a/pkg/cert/options.go +++ b/pkg/cert/options.go @@ -1,3 +1,19 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package cert import "time" diff --git a/pkg/controller/add_namespace.go b/pkg/controller/add_namespace.go deleted file mode 100644 index a6c79b8e..00000000 --- a/pkg/controller/add_namespace.go +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -import "github.com/clastix/capsule/pkg/controller/namespace" - -func init() { - // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. - AddToManagerFuncs = append(AddToManagerFuncs, namespace.Add) -} diff --git a/pkg/controller/add_secret.go b/pkg/controller/add_secret.go deleted file mode 100644 index c758cddf..00000000 --- a/pkg/controller/add_secret.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -import ( - "github.com/clastix/capsule/pkg/controller/secret" -) - -func init() { - // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. - AddToManagerFuncs = append(AddToManagerFuncs, secret.AddTls, secret.AddCa) -} diff --git a/pkg/controller/add_tenant.go b/pkg/controller/add_tenant.go deleted file mode 100644 index f63da8e8..00000000 --- a/pkg/controller/add_tenant.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -import ( - "github.com/clastix/capsule/pkg/controller/tenant" -) - -func init() { - // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. - AddToManagerFuncs = append(AddToManagerFuncs, tenant.Add) -} diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go deleted file mode 100644 index 5145d815..00000000 --- a/pkg/controller/controller.go +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package controller - -import ( - "sigs.k8s.io/controller-runtime/pkg/manager" -) - -// AddToManagerFuncs is a list of functions to add all Controllers to the Manager -var AddToManagerFuncs []func(manager.Manager) error - -// AddToManager adds all Controllers to the Manager -func AddToManager(m manager.Manager) error { - for _, f := range AddToManagerFuncs { - if err := f(m); err != nil { - return err - } - } - return nil -} diff --git a/pkg/controller/secret/errors.go b/pkg/controller/secret/errors.go deleted file mode 100644 index 36af5937..00000000 --- a/pkg/controller/secret/errors.go +++ /dev/null @@ -1,8 +0,0 @@ -package secret - -type MissingCaError struct { -} - -func (MissingCaError) Error() string { - return "CA has not been created yet, please generate a new" -} diff --git a/pkg/controller/secret/reconciler.go b/pkg/controller/secret/reconciler.go deleted file mode 100644 index 7cb3d1c4..00000000 --- a/pkg/controller/secret/reconciler.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package secret - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/clastix/capsule/pkg/cert" -) - -type secretReconciliationFunc func(reconciler *ReconcileSecret, request reconcile.Request) (reconcile.Result, error) - -// ReconcileSecret reconciles a Secret object -type ReconcileSecret struct { - client client.Client - scheme *runtime.Scheme - logger logr.Logger - reconcileFunc secretReconciliationFunc -} - -func newReconciler(mgr manager.Manager, name string, f secretReconciliationFunc) reconcile.Reconciler { - return &ReconcileSecret{ - client: mgr.GetClient(), - scheme: mgr.GetScheme(), - logger: log.Log.WithName(name), - reconcileFunc: f, - } -} - -func (r *ReconcileSecret) Reconcile(request reconcile.Request) (reconcile.Result, error) { - return r.reconcileFunc(r, request) -} - -func (r *ReconcileSecret) GetCertificateAuthority() (ca cert.Ca, err error) { - instance := &corev1.Secret{} - - err = r.client.Get(context.TODO(), types.NamespacedName{ - Namespace: "capsule-system", - Name: CaSecretName, - }, instance) - if err != nil { - return nil, fmt.Errorf("missing secret %s, cannot reconcile", CaSecretName) - } - - if instance.Data == nil { - return nil, MissingCaError{} - } - - ca, err = cert.NewCertificateAuthorityFromBytes(instance.Data[Cert], instance.Data[PrivateKey]) - if err != nil { - return - } - - return -} - -func filterByName(objName, desired string) bool { - return objName == desired -} diff --git a/pkg/controller/secret/secret_ca_controller.go b/pkg/controller/secret/secret_ca_controller.go deleted file mode 100644 index 2b860af1..00000000 --- a/pkg/controller/secret/secret_ca_controller.go +++ /dev/null @@ -1,180 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package secret - -import ( - "bytes" - "context" - "errors" - "time" - - v1 "k8s.io/api/admissionregistration/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/retry" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/clastix/capsule/pkg/cert" -) - -// Add creates a new Secret Controller and adds it to the Manager. The Manager will set fields on the Controller -// and Start it when the Manager is Started. -func AddCa(mgr manager.Manager) error { - r := newReconciler(mgr, "controller_secret", caReconcile) - return ca(mgr, r) -} - -// add adds a new Controller to mgr with r as the reconcile.Reconciler -func ca(mgr manager.Manager, r reconcile.Reconciler) error { - // Create a new controller - c, err := controller.New("secret-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - - // Watch for changes to CA Secret - err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForObject{}, predicate.Funcs{ - CreateFunc: func(event event.CreateEvent) (ok bool) { - return filterByName(event.Meta.GetName(), CaSecretName) - }, - DeleteFunc: func(deleteEvent event.DeleteEvent) bool { - return filterByName(deleteEvent.Meta.GetName(), CaSecretName) - }, - UpdateFunc: func(updateEvent event.UpdateEvent) bool { - return filterByName(updateEvent.MetaNew.GetName(), CaSecretName) - }, - GenericFunc: func(genericEvent event.GenericEvent) bool { - return filterByName(genericEvent.Meta.GetName(), CaSecretName) - }, - }) - if err != nil { - return err - } - - return nil -} - -func caReconcile(r *ReconcileSecret, request reconcile.Request) (reconcile.Result, error) { - var err error - - r.logger = r.logger.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) - r.logger.Info("Reconciling CA Secret") - - // Fetch the CA instance - instance := &corev1.Secret{} - err = r.client.Get(context.TODO(), request.NamespacedName, instance) - if err != nil { - // Error reading the object - requeue the request. - return reconcile.Result{}, err - } - - var ca cert.Ca - var rq time.Duration - ca, err = r.GetCertificateAuthority() - if err != nil && errors.Is(err, MissingCaError{}) { - ca, err = cert.GenerateCertificateAuthority() - if err != nil { - return reconcile.Result{}, err - } - } else if err != nil { - return reconcile.Result{}, err - } - - r.logger.Info("Handling CA Secret") - - rq, err = ca.ExpiresIn(time.Now()) - if err != nil { - r.logger.Info("CA is expired, cleaning to obtain a new one") - instance.Data = map[string][]byte{} - } else { - r.logger.Info("Updating CA secret with new PEM and RSA") - - var crt *bytes.Buffer - var key *bytes.Buffer - crt, _ = ca.CaCertificatePem() - key, _ = ca.CaPrivateKeyPem() - - instance.Data = map[string][]byte{ - Cert: crt.Bytes(), - PrivateKey: key.Bytes(), - } - - wh := &v1.MutatingWebhookConfiguration{} - err = r.client.Get(context.TODO(), types.NamespacedName{ - Name: "capsule", - }, wh) - if err != nil { - r.logger.Error(err, "cannot retrieve MutatingWebhookConfiguration") - return reconcile.Result{}, err - } - for i, w := range wh.Webhooks { - // Updating CABundle only in case of an internal service reference - if w.ClientConfig.Service != nil { - wh.Webhooks[i].ClientConfig.CABundle = instance.Data[Cert] - } - } - err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { - return r.client.Update(context.TODO(), wh, &client.UpdateOptions{}) - }) - if err != nil { - r.logger.Error(err, "cannot update MutatingWebhookConfiguration webhooks CA bundle") - return reconcile.Result{}, err - } - } - - var res controllerutil.OperationResult - t := &corev1.Secret{ObjectMeta: instance.ObjectMeta} - res, err = controllerutil.CreateOrUpdate(context.TODO(), r.client, t, func() error { - t.Data = instance.Data - return nil - }) - if err != nil { - r.logger.Error(err, "cannot update Capsule TLS") - return reconcile.Result{}, err - } - - if res == controllerutil.OperationResultUpdated { - r.logger.Info("Capsule CA has been updated, we need to trigger TLS update too") - tls := &corev1.Secret{} - err = r.client.Get(context.TODO(), types.NamespacedName{ - Namespace: "capsule-system", - Name: TlsSecretName, - }, tls) - if err != nil { - r.logger.Error(err, "Capsule TLS Secret missing") - } - err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - _, err = controllerutil.CreateOrUpdate(context.TODO(), r.client, tls, func() error { - tls.Data = map[string][]byte{} - return nil - }) - return err - }) - if err != nil { - r.logger.Error(err, "Cannot clean Capsule TLS Secret due to CA update") - return reconcile.Result{}, err - } - } - - r.logger.Info("Reconciliation completed, processing back in " + rq.String()) - return reconcile.Result{Requeue: true, RequeueAfter: rq}, nil -} diff --git a/pkg/controller/secret/secret_tls_controller.go b/pkg/controller/secret/secret_tls_controller.go deleted file mode 100644 index 9955bae4..00000000 --- a/pkg/controller/secret/secret_tls_controller.go +++ /dev/null @@ -1,150 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package secret - -import ( - "context" - "crypto/x509" - "encoding/pem" - "os" - "time" - - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/clastix/capsule/pkg/cert" -) - -// Add creates a new Secret Controller and adds it to the Manager. The Manager will set fields on the Controller -// and Start it when the Manager is Started. -func AddTls(mgr manager.Manager) error { - return tls(mgr, newReconciler(mgr, "controller_secret_tls", tlsReconcile)) -} - -// add adds a new Controller to mgr with r as the reconcile.Reconciler -func tls(mgr manager.Manager, r reconcile.Reconciler) error { - // Create a new controller - c, err := controller.New("secret-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - - // Watch for changes to TLS Secret - err = c.Watch(&source.Kind{Type: &corev1.Secret{}}, &handler.EnqueueRequestForObject{}, predicate.Funcs{ - CreateFunc: func(event event.CreateEvent) (ok bool) { - return filterByName(event.Meta.GetName(), TlsSecretName) - }, - DeleteFunc: func(deleteEvent event.DeleteEvent) bool { - return filterByName(deleteEvent.Meta.GetName(), TlsSecretName) - }, - UpdateFunc: func(updateEvent event.UpdateEvent) bool { - return filterByName(updateEvent.MetaNew.GetName(), TlsSecretName) - }, - GenericFunc: func(genericEvent event.GenericEvent) bool { - return filterByName(genericEvent.Meta.GetName(), TlsSecretName) - }, - }) - if err != nil { - return err - } - - return nil -} - -func tlsReconcile(r *ReconcileSecret, request reconcile.Request) (reconcile.Result, error) { - var err error - - r.logger = r.logger.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) - r.logger.Info("Reconciling TLS/CA Secret") - - // Fetch the Secret instance - instance := &corev1.Secret{} - err = r.client.Get(context.TODO(), request.NamespacedName, instance) - if err != nil { - // Error reading the object - requeue the request. - return reconcile.Result{}, err - } - - var ca cert.Ca - var rq time.Duration - - ca, err = r.GetCertificateAuthority() - if err != nil { - return reconcile.Result{}, err - } - - var shouldCreate bool - for _, key := range []string{Cert, PrivateKey} { - if _, ok := instance.Data[key]; !ok { - shouldCreate = true - } - } - - if shouldCreate { - r.logger.Info("Missing Capsule TLS certificate") - rq = 6 * 30 * 24 * time.Hour - - opts := cert.NewCertOpts(time.Now().Add(rq), "capsule.capsule-system.svc") - crt, key, err := ca.GenerateCertificate(opts) - if err != nil { - r.logger.Error(err, "Cannot generate new TLS certificate") - return reconcile.Result{}, err - } - instance.Data = map[string][]byte{ - Cert: crt.Bytes(), - PrivateKey: key.Bytes(), - } - } else { - var c *x509.Certificate - var b *pem.Block - b, _ = pem.Decode(instance.Data[Cert]) - c, err = x509.ParseCertificate(b.Bytes) - if err != nil { - r.logger.Error(err, "cannot parse Capsule TLS") - return reconcile.Result{}, err - } - - rq = time.Duration(c.NotAfter.Unix()-time.Now().Unix()) * time.Second - if time.Now().After(c.NotAfter) { - r.logger.Info("Capsule TLS is expired, cleaning to obtain a new one") - instance.Data = map[string][]byte{} - } - } - - var res controllerutil.OperationResult - t := &corev1.Secret{ObjectMeta: instance.ObjectMeta} - res, err = controllerutil.CreateOrUpdate(context.TODO(), r.client, t, func() error { - t.Data = instance.Data - return nil - }) - if err != nil { - r.logger.Error(err, "cannot update Capsule TLS") - return reconcile.Result{}, err - } - - if instance.Name == TlsSecretName && res == controllerutil.OperationResultUpdated { - r.logger.Info("Capsule TLS certificates has been updated, we need to restart the Controller") - os.Exit(15) - } - - r.logger.Info("Reconciliation completed, processing back in " + rq.String()) - return reconcile.Result{Requeue: true, RequeueAfter: rq}, nil -} diff --git a/pkg/indexer/add_namespaces.go b/pkg/indexer/add_namespaces.go index bd3d806e..be97eb05 100644 --- a/pkg/indexer/add_namespaces.go +++ b/pkg/indexer/add_namespaces.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/indexer/add_owner.go b/pkg/indexer/add_owner.go index 02902cce..6b8734ca 100644 --- a/pkg/indexer/add_owner.go +++ b/pkg/indexer/add_owner.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/indexer/indexer.go b/pkg/indexer/indexer.go index 9a726358..77f48002 100644 --- a/pkg/indexer/indexer.go +++ b/pkg/indexer/indexer.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/pkg/indexer/tenant/namespaces.go b/pkg/indexer/tenant/namespaces.go index 241faef4..75696896 100644 --- a/pkg/indexer/tenant/namespaces.go +++ b/pkg/indexer/tenant/namespaces.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,7 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" + "github.com/clastix/capsule/api/v1alpha1" ) type NamespacesReference struct { diff --git a/pkg/indexer/tenant/owner.go b/pkg/indexer/tenant/owner.go index f799eed2..50d329c5 100644 --- a/pkg/indexer/tenant/owner.go +++ b/pkg/indexer/tenant/owner.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,7 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" + "github.com/clastix/capsule/api/v1alpha1" ) type OwnerReference struct { diff --git a/pkg/webhook/utils/utils.go b/pkg/utils/user_group.go similarity index 91% rename from pkg/webhook/utils/utils.go rename to pkg/utils/user_group.go index f95f1c2d..a56d3321 100644 --- a/pkg/webhook/utils/utils.go +++ b/pkg/utils/user_group.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,7 +20,7 @@ import ( "sort" "strings" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" + "github.com/clastix/capsule/api/v1alpha1" ) type UserGroupList []string @@ -35,7 +38,7 @@ func (u UserGroupList) Swap(i, j int) { } func (u UserGroupList) IsInCapsuleGroup() (ok bool) { - v := v1alpha1.SchemeGroupVersion.Group + v := v1alpha1.GroupVersion.Group sort.Sort(u) i := sort.SearchStrings(u, v) diff --git a/pkg/webhook/add_namespace_quota.go b/pkg/webhook/add_namespace_quota.go deleted file mode 100644 index cde61916..00000000 --- a/pkg/webhook/add_namespace_quota.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package webhook - -import ( - "github.com/clastix/capsule/pkg/webhook/namespace_quota" -) - -func init() { - AddToWebhookServer = append(AddToWebhookServer, namespace_quota.Add) -} diff --git a/pkg/webhook/add_ingress_class.go b/pkg/webhook/handler.go similarity index 53% rename from pkg/webhook/add_ingress_class.go rename to pkg/webhook/handler.go index 67dfed95..4314b472 100644 --- a/pkg/webhook/add_ingress_class.go +++ b/pkg/webhook/handler.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,9 +17,14 @@ limitations under the License. package webhook import ( - "github.com/clastix/capsule/pkg/webhook/ingress_class" + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" ) -func init() { - AddToWebhookServer = append(AddToWebhookServer, ingress_class.AddExtensions, ingress_class.AddNetworking) +type Handler interface { + OnCreate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response + OnDelete(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response + OnUpdate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response } diff --git a/pkg/apis/apis.go b/pkg/webhook/ingress/errors.go similarity index 62% rename from pkg/apis/apis.go rename to pkg/webhook/ingress/errors.go index 04bfefea..de043f8c 100644 --- a/pkg/apis/apis.go +++ b/pkg/webhook/ingress/errors.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,16 +14,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -package apis +package ingress import ( - "k8s.io/apimachinery/pkg/runtime" + "fmt" ) -// AddToSchemes may be used to add all resources defined in the project to a Scheme -var AddToSchemes runtime.SchemeBuilder - -// AddToScheme adds all Resources to the Scheme -func AddToScheme(s *runtime.Scheme) error { - return AddToSchemes.AddToScheme(s) +type ingressClassForbidden struct { + ingressClass string +} + +func NewIngressClassForbidden(ingressClass string) error { + return &ingressClassForbidden{ingressClass: ingressClass} +} + +func (i ingressClassForbidden) Error() string { + return fmt.Sprintf("Ingress Class %s is forbidden for the current Tenant", i.ingressClass) } diff --git a/pkg/webhook/ingress/extension.go b/pkg/webhook/ingress/extension.go new file mode 100644 index 00000000..ddbd6b0d --- /dev/null +++ b/pkg/webhook/ingress/extension.go @@ -0,0 +1,69 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ingress + +import ( + "context" + "net/http" + + extensionsv1beta1 "k8s.io/api/extensions/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/clastix/capsule/pkg/webhook" +) + +// +kubebuilder:webhook:path=/validating-v1-extensions-ingress,mutating=false,failurePolicy=fail,groups=extensions,resources=ingresses,verbs=create;update,versions=v1beta1,name=extensions.ingress.capsule.clastix.io + +type ExtensionIngress struct{} + +func (r *ExtensionIngress) GetHandler() webhook.Handler { + return &extensionIngressHandler{} +} + +func (r *ExtensionIngress) GetName() string { + return "ExtensionIngress" +} + +func (r *ExtensionIngress) GetPath() string { + return "/validating-v1-extensions-ingress" +} + +type extensionIngressHandler struct { +} + +func (r *extensionIngressHandler) OnCreate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + i := &extensionsv1beta1.Ingress{} + if err := decoder.Decode(req, i); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + return handleIngress(ctx, i, i.Spec.IngressClassName, client) +} + +func (r *extensionIngressHandler) OnDelete(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Allowed("") +} + +func (r *extensionIngressHandler) OnUpdate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + i := &extensionsv1beta1.Ingress{} + if err := decoder.Decode(req, i); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + return handleIngress(ctx, i, i.Spec.IngressClassName, client) +} diff --git a/pkg/webhook/ingress_class/handler.go b/pkg/webhook/ingress/handler.go similarity index 87% rename from pkg/webhook/ingress_class/handler.go rename to pkg/webhook/ingress/handler.go index aa0255b1..19695130 100644 --- a/pkg/webhook/ingress_class/handler.go +++ b/pkg/webhook/ingress/handler.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package ingress_class +package ingress import ( "context" @@ -23,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" + "github.com/clastix/capsule/api/v1alpha1" ) func handleIngress(ctx context.Context, object metav1.Object, ic *string, c client.Client) admission.Response { @@ -43,8 +46,7 @@ func handleIngress(ctx context.Context, object metav1.Object, ic *string, c clie } if !tl.Items[0].Spec.IngressClasses.IsStringInList(*ic) { - err := fmt.Errorf("Ingress Class %s is forbidden for the current Tenant", *ic) - return admission.Errored(http.StatusBadRequest, err) + return admission.Errored(http.StatusBadRequest, NewIngressClassForbidden(*ic)) } return admission.Allowed("") diff --git a/pkg/webhook/ingress/networking.go b/pkg/webhook/ingress/networking.go new file mode 100644 index 00000000..ed80ebfc --- /dev/null +++ b/pkg/webhook/ingress/networking.go @@ -0,0 +1,67 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ingress + +import ( + "context" + "net/http" + + networkingv1beta1 "k8s.io/api/networking/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/clastix/capsule/pkg/webhook" +) + +// +kubebuilder:webhook:path=/validating-v1-networking-ingress,mutating=false,failurePolicy=fail,groups=networking.k8s.io,resources=ingresses,verbs=create;update,versions=v1beta1,name=networking.ingress.capsule.clastix.io + +type NetworkIngress struct{} + +func (r *NetworkIngress) GetHandler() webhook.Handler { + return &handler{} +} + +func (r *NetworkIngress) GetName() string { + return "NetworkIngress" +} + +func (r *NetworkIngress) GetPath() string { + return "/validating-v1-networking-ingress" +} + +type handler struct { +} + +func (r *handler) OnCreate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + i := &networkingv1beta1.Ingress{} + if err := decoder.Decode(req, i); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + return handleIngress(ctx, i, i.Spec.IngressClassName, client) +} + +func (r *handler) OnDelete(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Allowed("") +} + +func (r *handler) OnUpdate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + i := &networkingv1beta1.Ingress{} + if err := decoder.Decode(req, i); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + return handleIngress(ctx, i, i.Spec.IngressClassName, client) +} diff --git a/pkg/webhook/ingress_class/extension.go b/pkg/webhook/ingress_class/extension.go deleted file mode 100644 index caba3c3c..00000000 --- a/pkg/webhook/ingress_class/extension.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ingress_class - -import ( - "context" - "net/http" - - extensionsv1beta1 "k8s.io/api/extensions/v1beta1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - "github.com/clastix/capsule/pkg/webhook/utils" -) - -func AddExtensions(mgr manager.Manager) error { - mgr.GetWebhookServer().Register("/validating-v1-extensions-ingress", &webhook.Admission{ - Handler: &extensionIngress{}, - }) - return nil -} - -type extensionIngress struct { - client client.Client - decoder *admission.Decoder -} - -func (r *extensionIngress) Handle(ctx context.Context, req admission.Request) admission.Response { - g := utils.UserGroupList(req.UserInfo.Groups) - if !g.IsInCapsuleGroup() { - // not a Capsule user, can be skipped - return admission.Allowed("") - } - - i := &extensionsv1beta1.Ingress{} - if err := r.decoder.Decode(req, i); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - return handleIngress(ctx, i, i.Spec.IngressClassName, r.client) -} - -func (r *extensionIngress) InjectDecoder(d *admission.Decoder) error { - r.decoder = d - return nil -} - -func (r *extensionIngress) InjectClient(c client.Client) error { - r.client = c - return nil -} diff --git a/pkg/webhook/ingress_class/networking.go b/pkg/webhook/ingress_class/networking.go deleted file mode 100644 index 2093a0b4..00000000 --- a/pkg/webhook/ingress_class/networking.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2020 Clastix Labs. -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package ingress_class - -import ( - "context" - "net/http" - - networkingv1beta1 "k8s.io/api/networking/v1beta1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - - "github.com/clastix/capsule/pkg/webhook/utils" -) - -func AddNetworking(mgr manager.Manager) error { - mgr.GetWebhookServer().Register("/validating-v1-networking-ingress", &webhook.Admission{ - Handler: &validatingV1{}, - }) - return nil -} - -type validatingV1 struct { - client client.Client - decoder *admission.Decoder -} - -func (r *validatingV1) Handle(ctx context.Context, req admission.Request) admission.Response { - g := utils.UserGroupList(req.UserInfo.Groups) - if !g.IsInCapsuleGroup() { - // not a Capsule user, can be skipped - return admission.Allowed("") - } - - i := &networkingv1beta1.Ingress{} - if err := r.decoder.Decode(req, i); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - - return handleIngress(ctx, i, i.Spec.IngressClassName, r.client) -} - -func (r *validatingV1) InjectDecoder(d *admission.Decoder) error { - r.decoder = d - return nil -} - -func (r *validatingV1) InjectClient(c client.Client) error { - r.client = c - return nil -} diff --git a/pkg/webhook/add_network_policy.go b/pkg/webhook/namespace_quota/errors.go similarity index 65% rename from pkg/webhook/add_network_policy.go rename to pkg/webhook/namespace_quota/errors.go index 333feeca..1e060212 100644 --- a/pkg/webhook/add_network_policy.go +++ b/pkg/webhook/namespace_quota/errors.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -11,10 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package webhook +package namespace_quota -import "github.com/clastix/capsule/pkg/webhook/network_policies" +type namespaceQuotaExceededError struct{} -func init() { - AddToWebhookServer = append(AddToWebhookServer, network_policies.Add) +func NewNamespaceQuotaExceededError() error { + return &namespaceQuotaExceededError{} +} + +func (namespaceQuotaExceededError) Error() string { + return "Cannot exceed Namespace quota: please, reach out the system administrators" } diff --git a/pkg/webhook/namespace_quota/validating.go b/pkg/webhook/namespace_quota/validating.go index 4dabac05..c9d6a5d6 100644 --- a/pkg/webhook/namespace_quota/validating.go +++ b/pkg/webhook/namespace_quota/validating.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,52 +23,55 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" + "github.com/clastix/capsule/api/v1alpha1" + "github.com/clastix/capsule/pkg/webhook" ) -func Add(mgr manager.Manager) error { - mgr.GetWebhookServer().Register("/validate-v1-namespace-quota", &webhook.Admission{ - Handler: &nsQuota{}, - }) - return nil +// +kubebuilder:webhook:path=/validate-v1-namespace-quota,mutating=false,failurePolicy=fail,groups="",resources=namespaces,verbs=create,versions=v1,name=quota.namespace.capsule.clastix.io + +type Webhook struct{} + +func (r *Webhook) GetHandler() webhook.Handler { + return &handler{} } -type nsQuota struct { - client client.Client - decoder *admission.Decoder +func (r *Webhook) GetName() string { + return "NamespaceQuota" } -func (r *nsQuota) Handle(ctx context.Context, req admission.Request) admission.Response { - // Decoding the NS +func (r *Webhook) GetPath() string { + return "/validate-v1-namespace-quota" +} + +type handler struct { +} + +func (r *handler) OnCreate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { ns := &corev1.Namespace{} - if err := r.decoder.Decode(req, ns); err != nil { + if err := decoder.Decode(req, ns); err != nil { return admission.Errored(http.StatusBadRequest, err) } for _, or := range ns.ObjectMeta.OwnerReferences { // retrieving the selected Tenant t := &v1alpha1.Tenant{} - if err := r.client.Get(ctx, types.NamespacedName{Name: or.Name}, t); err != nil { + if err := client.Get(ctx, types.NamespacedName{Name: or.Name}, t); err != nil { return admission.Errored(http.StatusBadRequest, err) } if t.IsFull() { - return admission.Denied("Cannot exceed Namespace quota: please, reach out the system administrators") + return admission.Denied(NewNamespaceQuotaExceededError().Error()) } } // creating NS that is not bounded to any Tenant return admission.Allowed("") } -func (r *nsQuota) InjectDecoder(d *admission.Decoder) error { - r.decoder = d - return nil +func (r *handler) OnDelete(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Allowed("") } -func (r *nsQuota) InjectClient(c client.Client) error { - r.client = c - return nil +func (r *handler) OnUpdate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Allowed("") } diff --git a/pkg/webhook/network_policies/validating.go b/pkg/webhook/network_policies/validating.go index c6e7f471..4a0fafae 100644 --- a/pkg/webhook/network_policies/validating.go +++ b/pkg/webhook/network_policies/validating.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,79 +20,75 @@ import ( "context" "net/http" - "k8s.io/api/admission/v1beta1" networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" - "github.com/clastix/capsule/pkg/webhook/utils" + "github.com/clastix/capsule/api/v1alpha1" + "github.com/clastix/capsule/pkg/webhook" ) -func Add(mgr manager.Manager) error { - mgr.GetWebhookServer().Register("/validating-v1-network-policy", &webhook.Admission{ - Handler: &validatingNetworkPolicy{}, - }) - return nil +// +kubebuilder:webhook:path=/validating-v1-network-policy,mutating=false,failurePolicy=fail,groups=networking.k8s.io,resources=networkpolicies,verbs=create;update;delete,versions=v1,name=validating.network-policy.capsule.clastix.io + +type Webhook struct{} + +func (n Webhook) GetHandler() webhook.Handler { + return &handler{} } -type validatingNetworkPolicy struct { - client client.Client - decoder *admission.Decoder +func (n Webhook) GetName() string { + return "NetworkPolicy" } -func (r *validatingNetworkPolicy) Handle(ctx context.Context, req admission.Request) admission.Response { - var err error +func (n Webhook) GetPath() string { + return "/validating-v1-network-policy" +} - g := utils.UserGroupList(req.UserInfo.Groups) - if !g.IsInCapsuleGroup() { - // not a Capsule user, can be skipped - return admission.Allowed("") - } +type handler struct { +} - np := &networkingv1.NetworkPolicy{} - switch req.Operation { - case v1beta1.Delete: - err := r.client.Get(ctx, types.NamespacedName{ - Namespace: req.AdmissionRequest.Namespace, - Name: req.AdmissionRequest.Name, - }, np) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - default: - if err := r.decoder.Decode(req, np); err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - err = r.client.Get(ctx, types.NamespacedName{ - Namespace: np.Namespace, - Name: np.Name, - }, np) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - } - - l, err := v1alpha1.GetTypeLabel(&v1alpha1.Tenant{}) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - if _, ok := np.GetLabels()[l]; ok { - return admission.Denied("Capsule Network Policies cannot be manipulated: please, reach out the system administrators") - } - - // manipulating user Network Policy: it's safe +func (r *handler) OnCreate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { return admission.Allowed("") } -func (r *validatingNetworkPolicy) InjectDecoder(d *admission.Decoder) error { - r.decoder = d - return nil +func (r *handler) generic(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) (bool, error) { + var err error + np := &networkingv1.NetworkPolicy{} + err = client.Get(ctx, types.NamespacedName{Namespace: req.AdmissionRequest.Namespace, Name: req.AdmissionRequest.Name}, np) + if err != nil { + return false, err + } + + return r.isCapsuleNetworkPolicy(np), nil } -func (r *validatingNetworkPolicy) InjectClient(c client.Client) error { - r.client = c - return nil + +func (r *handler) OnDelete(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + ok, err := r.generic(ctx, req, client, decoder) + if err != nil { + return admission.Errored(http.StatusInternalServerError, err) + } + if !ok { + return admission.Denied("Capsule Network Policies cannot be deleted: please, reach out the system administrators") + } + + return admission.Allowed("") +} + +func (r *handler) isCapsuleNetworkPolicy(np *networkingv1.NetworkPolicy) (ok bool) { + l, _ := v1alpha1.GetTypeLabel(&v1alpha1.Tenant{}) + _, ok = np.GetLabels()[l] + return +} + +func (r *handler) OnUpdate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + ok, err := r.generic(ctx, req, client, decoder) + if err != nil { + return admission.Errored(http.StatusInternalServerError, err) + } + if !ok { + return admission.Denied("Capsule Network Policies cannot be updated: please, reach out the system administrators") + } + + return admission.Allowed("") } diff --git a/pkg/webhook/owner_reference/patching.go b/pkg/webhook/owner_reference/patching.go index e373cb18..111419c0 100644 --- a/pkg/webhook/owner_reference/patching.go +++ b/pkg/webhook/owner_reference/patching.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,44 +27,37 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" - "github.com/clastix/capsule/pkg/webhook/utils" + "github.com/clastix/capsule/api/v1alpha1" + "github.com/clastix/capsule/pkg/webhook" ) -func Add(mgr manager.Manager) error { - mgr.GetWebhookServer() - mgr.GetWebhookServer().Register("/mutate-v1-namespace-owner-reference", &webhook.Admission{ - Handler: &ownerRef{ - schema: mgr.GetScheme(), - }, - }) - return nil +// +kubebuilder:webhook:path=/mutate-v1-namespace-owner-reference,mutating=true,failurePolicy=fail,groups="",resources=namespaces,verbs=create,versions=v1,name=owner.namespace.capsule.clastix.io + +type Webhook struct{} + +func (o Webhook) GetHandler() webhook.Handler { + return &handler{} } -type ownerRef struct { - client client.Client - decoder *admission.Decoder - // injecting the runtime.Scheme for controllerutil.SetOwnerReference - schema *runtime.Scheme +func (o Webhook) GetName() string { + return "OwnerReference" } -func (r *ownerRef) Handle(ctx context.Context, req admission.Request) admission.Response { - // Decoding the NS +func (o Webhook) GetPath() string { + return "/mutate-v1-namespace-owner-reference" +} + +type handler struct { +} + +func (r *handler) OnCreate(ctx context.Context, req admission.Request, clt client.Client, decoder *admission.Decoder) admission.Response { ns := &corev1.Namespace{} - if err := r.decoder.Decode(req, ns); err != nil { + if err := decoder.Decode(req, ns); err != nil { return admission.Errored(http.StatusBadRequest, err) } - g := utils.UserGroupList(req.UserInfo.Groups) - if !g.IsInCapsuleGroup() { - // user requested NS creation is not a Capsule user, so skipping the validation checks - return admission.Allowed("") - } - if len(ns.ObjectMeta.Labels) > 0 { ln, err := v1alpha1.GetTypeLabel(&v1alpha1.Tenant{}) if err != nil { @@ -72,7 +68,7 @@ func (r *ownerRef) Handle(ctx context.Context, req admission.Request) admission. if ok { // retrieving the selected Tenant t := &v1alpha1.Tenant{} - if err := r.client.Get(ctx, types.NamespacedName{Name: l}, t); err != nil { + if err := clt.Get(ctx, types.NamespacedName{Name: l}, t); err != nil { return admission.Errored(http.StatusBadRequest, err) } // Tenant owner must adhere to user that asked for NS creation @@ -86,7 +82,7 @@ func (r *ownerRef) Handle(ctx context.Context, req admission.Request) admission. } tl := &v1alpha1.TenantList{} - if err := r.client.List(ctx, tl, client.MatchingFieldsSelector{ + if err := clt.List(ctx, tl, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".spec.owner", req.UserInfo.Username), }); err != nil { return admission.Errored(http.StatusBadRequest, err) @@ -99,21 +95,23 @@ func (r *ownerRef) Handle(ctx context.Context, req admission.Request) admission. return admission.Denied("You do not have any Tenant assigned: please, reach out the system administrators") } -func (r *ownerRef) patchResponseForOwnerRef(tenant *v1alpha1.Tenant, ns *corev1.Namespace) admission.Response { +func (r *handler) OnDelete(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Allowed("") +} + +func (r *handler) OnUpdate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Denied("Capsule user cannot update a Namespace") +} + +func (r *handler) patchResponseForOwnerRef(tenant *v1alpha1.Tenant, ns *corev1.Namespace) admission.Response { + scheme := runtime.NewScheme() + _ = v1alpha1.AddToScheme(scheme) + _ = corev1.AddToScheme(scheme) + o, _ := json.Marshal(ns.DeepCopy()) - if err := controllerutil.SetControllerReference(tenant, ns, r.schema); err != nil { + if err := controllerutil.SetControllerReference(tenant, ns, scheme); err != nil { return admission.Errored(http.StatusInternalServerError, err) } c, _ := json.Marshal(ns) return admission.PatchResponseFromRaw(o, c) } - -func (r *ownerRef) InjectDecoder(d *admission.Decoder) error { - r.decoder = d - return nil -} - -func (r *ownerRef) InjectClient(c client.Client) error { - r.client = c - return nil -} diff --git a/pkg/webhook/pvc/errors.go b/pkg/webhook/pvc/errors.go new file mode 100644 index 00000000..a8cd16d9 --- /dev/null +++ b/pkg/webhook/pvc/errors.go @@ -0,0 +1,43 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package pvc + +import ( + "fmt" +) + +type validStorageClassError struct{} + +func NewValidStorageClassError() error { + return &validStorageClassError{} +} + +func (validStorageClassError) Error() string { + return "A valid Strage Class must be used" +} + +type forbiddenStorageClassError struct { + storageClassName string +} + +func NewForbiddenStorageClassError(storageClassName string) error { + return &forbiddenStorageClassError{storageClassName: storageClassName} +} + +func (f forbiddenStorageClassError) Error() string { + return fmt.Sprintf("Storage Class %s is forbidden for the current Tenant", f.storageClassName) +} diff --git a/pkg/webhook/pvc/validating.go b/pkg/webhook/pvc/validating.go index bd018123..1432acb4 100644 --- a/pkg/webhook/pvc/validating.go +++ b/pkg/webhook/pvc/validating.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,70 +18,66 @@ package pvc import ( "context" - "fmt" "net/http" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/fields" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/webhook" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" - "github.com/clastix/capsule/pkg/apis/capsule/v1alpha1" - "github.com/clastix/capsule/pkg/webhook/utils" + "github.com/clastix/capsule/api/v1alpha1" + "github.com/clastix/capsule/pkg/webhook" ) -func Add(mgr manager.Manager) error { - mgr.GetWebhookServer().Register("/validating-v1-pvc", &webhook.Admission{ - Handler: &validatindPvc{}, - }) - return nil +// +kubebuilder:webhook:path=/validating-v1-pvc,mutating=false,failurePolicy=fail,groups="",resources=persistentvolumeclaims,verbs=create,versions=v1,name=pvc.capsule.clastix.io + +type Webhook struct{} + +func (p Webhook) GetName() string { + return "Pvc" } -type validatindPvc struct { - client client.Client - decoder *admission.Decoder +func (p Webhook) GetPath() string { + return "/validating-v1-pvc" } -func (r *validatindPvc) Handle(ctx context.Context, req admission.Request) admission.Response { - g := utils.UserGroupList(req.UserInfo.Groups) - if !g.IsInCapsuleGroup() { - // not a Capsule user, can be skipped - return admission.Allowed("") - } +func (p Webhook) GetHandler() webhook.Handler { + return &handler{} +} +type handler struct { +} + +func (r *handler) OnCreate(ctx context.Context, req admission.Request, c client.Client, decoder *admission.Decoder) admission.Response { pvc := &v1.PersistentVolumeClaim{} - if err := r.decoder.Decode(req, pvc); err != nil { + + if err := decoder.Decode(req, pvc); err != nil { return admission.Errored(http.StatusBadRequest, err) } if pvc.Spec.StorageClassName == nil { - return admission.Errored(http.StatusBadRequest, fmt.Errorf("A valid Strage Class must be used")) + return admission.Errored(http.StatusBadRequest, NewValidStorageClassError()) } sc := *pvc.Spec.StorageClassName tl := &v1alpha1.TenantList{} - if err := r.client.List(ctx, tl, client.MatchingFieldsSelector{ + if err := c.List(ctx, tl, client.MatchingFieldsSelector{ Selector: fields.OneTermEqualSelector(".status.namespaces", pvc.Namespace), }); err != nil { return admission.Errored(http.StatusBadRequest, err) } if !tl.Items[0].Spec.StorageClasses.IsStringInList(sc) { - err := fmt.Errorf("Storage Class %s is forbidden for the current Tenant", *pvc.Spec.StorageClassName) - return admission.Errored(http.StatusBadRequest, err) + return admission.Errored(http.StatusBadRequest, NewForbiddenStorageClassError(*pvc.Spec.StorageClassName)) } return admission.Allowed("") } -func (r *validatindPvc) InjectDecoder(d *admission.Decoder) error { - r.decoder = d - return nil +func (r *handler) OnDelete(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Allowed("") } -func (r *validatindPvc) InjectClient(c client.Client) error { - r.client = c - return nil +func (r *handler) OnUpdate(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) admission.Response { + return admission.Allowed("") } diff --git a/pkg/webhook/router.go b/pkg/webhook/router.go new file mode 100644 index 00000000..c2f992b4 --- /dev/null +++ b/pkg/webhook/router.go @@ -0,0 +1,82 @@ +/* +Copyright 2020 Clastix Labs. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package webhook + +import ( + "context" + "io/ioutil" + + admissionv1beta1 "k8s.io/api/admission/v1beta1" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + "github.com/clastix/capsule/pkg/utils" +) + +func Register(mgr controllerruntime.Manager, webhookList ...Webhook) error { + // skipping webhook setup if certificate is missing + dat, _ := ioutil.ReadFile("/tmp/k8s-webhook-server/serving-certs/tls.crt") + if len(dat) == 0 { + return nil + } + + s := mgr.GetWebhookServer() + for _, wh := range webhookList { + s.Register(wh.GetPath(), &webhook.Admission{ + Handler: &handlerRouter{ + handler: wh.GetHandler(), + }, + }) + } + return nil +} + +type handlerRouter struct { + handler Handler + client client.Client + decoder *admission.Decoder +} + +func (r *handlerRouter) Handle(ctx context.Context, req admission.Request) admission.Response { + if !utils.UserGroupList(req.UserInfo.Groups).IsInCapsuleGroup() { + // not a Capsule user, can be skipped + return admission.Allowed("") + } + + switch req.Operation { + case admissionv1beta1.Create: + return r.handler.OnCreate(ctx, req, r.client, r.decoder) + case admissionv1beta1.Update: + return r.handler.OnUpdate(ctx, req, r.client, r.decoder) + case admissionv1beta1.Delete: + return r.handler.OnDelete(ctx, req, r.client, r.decoder) + } + + return admission.Allowed("") +} + +func (r *handlerRouter) InjectClient(c client.Client) error { + r.client = c + return nil +} + +func (r *handlerRouter) InjectDecoder(d *admission.Decoder) error { + r.decoder = d + return nil +} diff --git a/pkg/webhook/webhook.go b/pkg/webhook/webhook.go index c497c416..e5723a51 100644 --- a/pkg/webhook/webhook.go +++ b/pkg/webhook/webhook.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -13,26 +16,8 @@ limitations under the License. package webhook -import ( - "io/ioutil" - - "sigs.k8s.io/controller-runtime/pkg/manager" -) - -// AddToWebhookServer is a list of functions to create webhooks and add them to a manager. -var AddToWebhookServer []func(manager2 manager.Manager) error - -// AddToServer adds all Controllers to the Manager -func AddToServer(mgr manager.Manager) error { - // skipping webhook setup if certificate is missing - dat, _ := ioutil.ReadFile("/tmp/k8s-webhook-server/serving-certs/tls.crt") - if len(dat) == 0 { - return nil - } - for _, f := range AddToWebhookServer { - if err := f(mgr); err != nil { - return err - } - } - return nil +type Webhook interface { + GetName() string + GetPath() string + GetHandler() Handler } diff --git a/tools.go b/tools.go deleted file mode 100644 index 3d5e5c0b..00000000 --- a/tools.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build tools - -// Place any runtime dependencies as imports in this file. -// Go modules will be forced to download and install them. -package tools diff --git a/version/version.go b/version/version.go index 57b1436e..e9e0f2a4 100644 --- a/version/version.go +++ b/version/version.go @@ -1,9 +1,12 @@ /* Copyright 2020 Clastix Labs. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -13,6 +16,4 @@ limitations under the License. package version -var ( - Version = "0.0.1" -) +var Version = "dev"