diff --git a/.ci/build-container.sh b/.ci/build-container.sh deleted file mode 100755 index f1971afe09..0000000000 --- a/.ci/build-container.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -if [ -z "${BUILD_IMAGE}" ]; then - echo "Build image not provided" - exit 1 -fi - -command -v "buildah" > /dev/null -if [ $? = 0 ]; then - echo "Using buildah" > build/_output/build-container.log - CMD="buildah bud" -else - echo "Using Docker" > build/_output/build-container.log - CMD="docker" -fi - -${CMD} -f build/Dockerfile -t ${BUILD_IMAGE} . >> build/_output/build-container.log 2>&1 \ No newline at end of file diff --git a/.ci/format.sh b/.ci/format.sh deleted file mode 100755 index 3f8fe66e4a..0000000000 --- a/.ci/format.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -GOFMT=goimports - -command -v ${GOFMT} > /dev/null -if [ $? != 0 ]; then - if [ -n "${GOPATH}" ]; then - GOFMT="${GOPATH}/bin/goimports" - fi -fi - -${GOFMT} -local "github.com/open-telemetry/opentelemetry-operator" -l -w $(git ls-files "*\.go" | grep -v vendor) diff --git a/.ci/generate.sh b/.ci/generate.sh deleted file mode 100755 index 2f429e5716..0000000000 --- a/.ci/generate.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -OPENAPIGEN=openapi-gen -command -v ${OPENAPIGEN} > /dev/null -if [ $? != 0 ]; then - if [ -n ${GOPATH} ]; then - OPENAPIGEN="${GOPATH}/bin/openapi-gen" - fi -fi - -CLIENTGEN=client-gen -command -v ${OPENAPIGEN} > /dev/null -if [ $? != 0 ]; then - if [ -n ${GOPATH} ]; then - CLIENTGEN="${GOPATH}/bin/client-gen" - fi -fi - -# generate the Kubernetes stubs -operator-sdk generate k8s -RT=$? -if [ ${RT} != 0 ]; then - echo "Failed to generate the Kubernetes stubs." - exit ${RT} -fi - -# generate the CRD(s) -operator-sdk generate crds -RT=$? -if [ ${RT} != 0 ]; then - echo "Failed to generate CRDs." - exit ${RT} -fi - -# generate the schema validation (openapi) stubs -${OPENAPIGEN} --logtostderr=true -o "" -i ./pkg/apis/opentelemetry/v1alpha1 -O zz_generated.openapi -p ./pkg/apis/opentelemetry/v1alpha1 -h /dev/null -r "-" -RT=$? -if [ ${RT} != 0 ]; then - echo "Failed to generate the openapi (schema validation) stubs." - exit ${RT} -fi - -# generate the clients -${CLIENTGEN} \ - --input "opentelemetry/v1alpha1" \ - --input-base github.com/open-telemetry/opentelemetry-operator/pkg/apis \ - --go-header-file /dev/null \ - --output-package github.com/open-telemetry/opentelemetry-operator/pkg/client \ - --clientset-name versioned \ - --output-base ../../../ -RT=$? -if [ ${RT} != 0 ]; then - echo "Failed to generate the OpenTelemetry Operator clients." - exit ${RT} -fi diff --git a/.ci/lint.sh b/.ci/lint.sh deleted file mode 100755 index c043be5c88..0000000000 --- a/.ci/lint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -GOLINT=golint - -command -v ${GOLINT} > /dev/null -if [ $? != 0 ]; then - if [ -n ${GOPATH} ]; then - GOLINT="${GOPATH}/bin/golint" - fi -fi - -out=$(${GOLINT} ./...) -if [[ $out ]]; then - echo "$out" - exit 1 -fi \ No newline at end of file diff --git a/.ci/publish-images.sh b/.ci/publish-images.sh deleted file mode 100755 index d227aced96..0000000000 --- a/.ci/publish-images.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -BASE_BUILD_IMAGE=${BASE_BUILD_IMAGE:-"opentelemetry/opentelemetry-operator"} -OPERATOR_VERSION=${OPERATOR_VERSION:-$(git describe --tags)} - -## if we are on a release tag, let's extract the version number -## the other possible value, currently, is 'master' (or another branch name) -## if we are not running in the CI, it fallsback to the `git describe` above -if [[ $OPERATOR_VERSION == v* ]]; then - OPERATOR_VERSION=$(echo ${OPERATOR_VERSION} | grep -Po "([\d\.]+)") - MAJOR_MINOR=$(echo ${OPERATOR_VERSION} | awk -F. '{print $1"."$2}') -fi - -BUILD_IMAGE=${BUILD_IMAGE:-"${BASE_BUILD_IMAGE}:${OPERATOR_VERSION}"} - -echo "Building image ${BUILD_IMAGE}" -make install-tools build container BUILD_IMAGE="${BUILD_IMAGE}" -RT=$? -if [ ${RT} != 0 ]; then - echo "Failed to build the operator's container image." - exit ${RT} -fi - -if [ -n "${MAJOR_MINOR}" ]; then - MAJOR_MINOR_IMAGE="${BASE_BUILD_IMAGE}:${MAJOR_MINOR}" - docker tag "${BUILD_IMAGE}" "${MAJOR_MINOR_IMAGE}" - docker push "${MAJOR_MINOR_IMAGE}" -fi - -## now, push to quay.io -if [ -n "${QUAY_USERNAME}" -a -n "${QUAY_PASSWORD}" ]; then - echo "Performing a 'docker login' for Quay" - echo "${QUAY_PASSWORD}" | docker login -u "${QUAY_USERNAME}" quay.io --password-stdin - - echo "Tagging ${BUILD_IMAGE} as quay.io/${BUILD_IMAGE}" - docker tag "${BUILD_IMAGE}" "quay.io/${BUILD_IMAGE}" - - echo "Pushing 'quay.io/${BUILD_IMAGE}'" - docker push "quay.io/${BUILD_IMAGE}" - - if [ -n "${MAJOR_MINOR_IMAGE}" ]; then - echo "Pushing 'quay.io/${MAJOR_MINOR_IMAGE}' to quay.io" - docker tag "${MAJOR_MINOR_IMAGE}" "quay.io/${MAJOR_MINOR_IMAGE}" - docker push "quay.io/${MAJOR_MINOR_IMAGE}" - fi -else - echo "Couldn't publish images to ${BUILD_IMAGE}, as the credentials aren't set" - exit 1 -fi diff --git a/.ci/release.sh b/.ci/release.sh deleted file mode 100755 index 36116550ae..0000000000 --- a/.ci/release.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash - -git diff -s --exit-code -if [[ $? != 0 ]]; then - echo "The repository isn't clean. We won't proceed, as we don't know if we should commit those changes or not." - exit 1 -fi - -BASE_BUILD_IMAGE=${BASE_BUILD_IMAGE:-"quay.io/opentelemetry/opentelemetry-operator"} -BASE_TAG=${BASE_TAG:-$(git describe --tags)} -OPERATOR_VERSION=${OPERATOR_VERSION:-${BASE_TAG}} -OPERATOR_VERSION=$(echo ${OPERATOR_VERSION} | grep -Po "([\d\.]+)") -TAG=${TAG:-"v${OPERATOR_VERSION}"} -BUILD_IMAGE=${BUILD_IMAGE:-"${BASE_BUILD_IMAGE}:${TAG}"} -CREATED_AT=$(date -u -Isecond) -PREVIOUS_VERSION=$(grep operator= opentelemetry.version | awk -F= '{print $2}') - -if [[ ${BASE_TAG} =~ ^release/v.[[:digit:].]+(\-.*)?$ ]]; then - echo "Releasing ${OPERATOR_VERSION} from ${BASE_TAG}" -else - echo "The release tag does not match the expected format: ${BASE_TAG}" - exit 1 -fi - -if [ -z "${GH_WRITE_TOKEN}" ]; then - echo "The GitHub write token isn't set. Skipping release process." - exit 1 -fi - -# changes to deploy/operator.yaml -sed "s~image: quay.io/opentelemetry/opentelemetry-operator.*~image: ${BUILD_IMAGE}~gi" -i deploy/operator.yaml - -# change the versions.txt -sed "s~operator=${PREVIOUS_VERSION}~operator=${OPERATOR_VERSION}~gi" -i opentelemetry.version - -operator-sdk olm-catalog gen-csv \ - --csv-channel=alpha \ - --default-channel \ - --operator-name opentelemetry-operator \ - --update-crds \ - --csv-version=${OPERATOR_VERSION} \ - --from-version=${PREVIOUS_VERSION} - -git diff -s --exit-code -if [[ $? == 0 ]]; then - echo "No changes detected. Skipping." -else - git add \ - deploy/olm-catalog/opentelemetry-operator/opentelemetry-operator.package.yaml \ - deploy/operator.yaml \ - opentelemetry.version \ - deploy/olm-catalog/opentelemetry-operator/${OPERATOR_VERSION}/ - - git diff -s --exit-code - if [[ $? != 0 ]]; then - echo "There are more changes than expected. Skipping the release." - git diff - exit 1 - fi - - git config user.email "opentelemetry-operator@opentelemetry.io" - git config user.name "OpenTelemetry Operator Release" - - git commit -qm "Release ${TAG}" - git tag ${TAG} - git push --repo=https://${GH_WRITE_TOKEN}@github.com/open-telemetry/opentelemetry-collector.git --tags - git push https://${GH_WRITE_TOKEN}@github.com/open-telemetry/opentelemetry-collector.git refs/tags/${TAG}:master -fi diff --git a/.ci/script.sh b/.ci/script.sh deleted file mode 100755 index ee09da1105..0000000000 --- a/.ci/script.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -if [ -z ${GOPATH} ]; then - export PATH="${HOME}/go/bin:${PATH}" -else - export PATH="${GOPATH}/bin:${PATH}" -fi - -make ci -RT=$? -if [ ${RT} != 0 ]; then - echo "Failed to build the operator." - exit ${RT} -fi diff --git a/.ci/upload-test-coverage.sh b/.ci/upload-test-coverage.sh deleted file mode 100755 index 38c878be60..0000000000 --- a/.ci/upload-test-coverage.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -bash <(curl -s https://codecov.io/bash) diff --git a/.codecov.yml b/.codecov.yml deleted file mode 100644 index a2ef66ad3f..0000000000 --- a/.codecov.yml +++ /dev/null @@ -1,3 +0,0 @@ -ignore: - - "./pkg/apis/opentelemetry/v1alpha1/zz_generated.deepcopy.go" - - "./pkg/apis/opentelemetry/v1alpha1/zz_generated.openapi.go" diff --git a/.github/workflows/continuous-integration.yaml b/.github/workflows/continuous-integration.yaml index cd4cf41941..2e27270708 100644 --- a/.github/workflows/continuous-integration.yaml +++ b/.github/workflows/continuous-integration.yaml @@ -3,15 +3,15 @@ on: [push, pull_request] jobs: unit-tests: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/setup-go@v1 with: go-version: '1.14.4' - uses: actions/checkout@v1 - - uses: jpkrohling/setup-operator-sdk@v1-release - with: - operator-sdk-version: v0.18.1 + + - name: "install kubebuilder" + run: ./hack/install-kubebuilder.sh - name: "basic checks" - run: ./.ci/script.sh + run: make ci diff --git a/.gitignore b/.gitignore index 6910dae07c..37a560510e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,78 +1,25 @@ -# Temporary Build Files -build/_output -build/_test -coverage.txt -# 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 +*.coverprofile + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 596646b66f..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,61 +0,0 @@ -# How to Contribute to the OpenTelemetry Operator for Kubernetes - -We'd love your help! - -This project is [Apache 2.0 licensed](LICENSE) and accepts contributions via GitHub pull requests. This document outlines some of the conventions on development workflow, commit message formatting, contact points and other resources to make it easier to get your contribution accepted. - -We gratefully welcome improvements to documentation as well as to code. - -## Certificate of Origin - -By contributing to this project you agree to the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This document was created by the Linux Kernel community and is a simple statement that you, as a contributor, have the legal right to make the contribution. See the [DCO](DCO) file for details. - -## Getting Started - -This project is a regular [Kubernetes Operator](https://coreos.com/operators/) built using the Operator SDK. Refer to the Operator SDK documentation to understand the basic architecture of this operator. - -### Installing the Operator SDK command line tool - -Follow the installation guidelines from [Operator SDK GitHub page](https://github.com/operator-framework/operator-sdk). - -### Developing - -As usual for operators following the Operator SDK in recent versions, the dependencies are managed using [`go modules`](https://golang.org/doc/go1.11#modules). Refer to that project's documentation for instructions on how to add or update dependencies. - -The first step is to get a local Kubernetes instance up and running. The recommended approach is using `minikube`. Refer to the Kubernetes' [documentation](https://kubernetes.io/docs/tasks/tools/install-minikube/) for instructions on how to install it. - -Once `minikube` is installed, it can be started with: - -``` -minikube start -``` - -NOTE: Make sure to read the documentation to learn the performance switches that can be applied to your platform. - -Once minikube has finished starting, get the Operator running: - -``` -make run -``` - -At this point, an OpenTelemetry Collector instance can be installed: - -``` -kubectl apply -f deploy/examples/simplest.yaml -kubectl get otelcols -kubectl get pods -``` - -To remove the instance: - -``` -kubectl delete -f deploy/examples/simplest.yaml -``` - -#### Model changes - -The Operator SDK generates the `pkg/apis/opentelemetry/v1alpha1//zz_generated.*.go` files via the command `make generate`. This should be executed whenever there's a model change (`pkg/apis/opentelemetry/v1alpha1//opentelemetrycollector_types.go`) - -#### Tests - -Right now, there are only unit tests in this repository. They can be executed via `make unit-tests`. End-to-end tests are planned, and should be executed via `make e2e-tests`. All tests, including unit and end-to-end, will be executed when `make test` is called. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..74eb9d7412 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +# 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/ + +# Build +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -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 ea32eb48db..2e0f3bee97 100644 --- a/Makefile +++ b/Makefile @@ -1,106 +1,143 @@ -OPERATOR_NAME ?= opentelemetry-operator -OPERATOR_VERSION ?= "$(shell git describe --tags)" +# Current Operator version +VERSION ?= "$(shell git describe --tags)" VERSION_DATE ?= $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') - -GO_FLAGS ?= GOOS=linux GOARCH=amd64 CGO_ENABLED=0 GO111MODULE=on -GOPATH ?= $(shell go env GOPATH) -KUBERNETES_CONFIG ?= "${HOME}/.kube/config" -WATCH_NAMESPACE ?= "" -BIN_DIR ?= "build/_output/bin" - -NAMESPACE ?= "quay.io/${USER}" -BUILD_IMAGE ?= "${NAMESPACE}/${OPERATOR_NAME}:latest" -OUTPUT_BINARY ?= "${BIN_DIR}/${OPERATOR_NAME}" -VERSION_PKG ?= "github.com/open-telemetry/opentelemetry-operator/pkg/version" -LD_FLAGS ?= "-X ${VERSION_PKG}.version=${OPERATOR_VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELSVC_VERSION}" - -OTELSVC_VERSION ?= "$(shell grep -v '\#' opentelemetry.version | grep opentelemetry-collector | awk -F= '{print $$2}')" - -.DEFAULT_GOAL := build - -.PHONY: discard-go-mod-changes -discard-go-mod-changes: - @# 'go list' will update go.mod/go.sum and there's no way to prevent it (not even with -mod=readonly) - @git checkout -- go.mod go.sum - -.PHONY: check -check: ensure-generate-is-noop discard-go-mod-changes - @echo Checking... - @git diff -s --exit-code . || (echo "Build failed: one or more source files aren't properly formatted. Run 'make format' and update your PR." && exit 1) - -.PHONY: ensure-generate-is-noop -ensure-generate-is-noop: generate format - @git diff -s --exit-code pkg/apis/opentelemetry/v1alpha1/zz_generated.*.go || (echo "Build failed: a model has been changed but the deep copy functions aren't up to date. Run 'make generate' and update your PR." && exit 1) - @git diff -s --exit-code pkg/client/versioned || (echo "Build failed: the versioned clients aren't up to date. Run 'make generate'." && exit 1) - -.PHONY: format -format: - @echo Formatting code... - @GOPATH=${GOPATH} .ci/format.sh - -.PHONY: security -security: - @echo Security... - @gosec -quiet ./... 2>/dev/null - -.PHONY: build -build: format - @echo Building operator binary... - @${GO_FLAGS} go build -o ${OUTPUT_BINARY} -ldflags ${LD_FLAGS} ./cmd/manager/main.go - -.PHONY: container -container: - @echo Building container ${BUILD_IMAGE}... - @mkdir -p build/_output - @BUILD_IMAGE=${BUILD_IMAGE} ./.ci/build-container.sh - -.PHONY: run -run: crd - @OPERATOR_NAME=${OPERATOR_NAME} operator-sdk run local --watch-namespace="${WATCH_NAMESPACE}" --operator-flags "--zap-devel" --go-ldflags ${LD_FLAGS} - -.PHONY: clean -clean: - @echo Cleaning... - -.PHONY: crd -crd: - @kubectl create -f deploy/crds/opentelemetry.io_opentelemetrycollectors_crd.yaml 2>&1 | grep -v "already exists" || true - -.PHONY: generate -generate: internal-generate format - -.PHONY: internal-generate -internal-generate: - @GOPATH=${GOPATH} ./.ci/generate.sh - -.PHONY: lint -lint: - @echo Linting... - @GOPATH=${GOPATH} ./.ci/lint.sh - -.PHONY: test -test: unit-tests - -.PHONY: unit-tests -unit-tests: - @echo Running unit tests... - @go test ./... -cover -coverprofile=coverage.txt -covermode=atomic -race - -.PHONY: all -all: check format lint security build test - -.PHONY: ci -ci: install-tools ensure-generate-is-noop all - -.PHONY: install-tools -install-tools: - @curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b ${GOPATH}/bin 2.0.0 - @go install \ - golang.org/x/tools/cmd/goimports \ - k8s.io/code-generator/cmd/client-gen \ - k8s.io/kube-openapi/cmd/openapi-gen - -.PHONY: install-prometheus-operator -install-prometheus-operator: - @echo Installing Prometheus Operator bundle - @kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/master/bundle.yaml +VERSION_PKG ?= "github.com/open-telemetry/opentelemetry-operator/internal/version" +OTELSVC_VERSION ?= "$(shell grep -v '\#' versions.txt | grep opentelemetry-collector | awk -F= '{print $$2}')" +LD_FLAGS ?= "-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELSVC_VERSION}" + +# Default bundle image tag +BUNDLE_IMG ?= controller-bundle:$(VERSION) +# 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) + +# Image URL to use all building/pushing image targets +IMG ?= controller:latest +# Produce CRDs that work back to Kubernetes 1.11 (no version conversion) +CRD_OPTIONS ?= "crd:trivialVersions=true" + +# 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 + +# If we are running in CI, run ginkgo with the recommended CI settings +ifeq (,$(CI)) +GINKGO_OPTS=-r +else +GINKGO_OPTS=-r --randomizeAllSpecs --randomizeSuites --failOnPending --cover --trace --race --progress --compilers=2 -v +endif + +all: manager +ci: test + +# Run tests +test: ginkgo generate fmt vet manifests + $(GINKGO) $(GINKGO_OPTS) + +# 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 -ldflags ${LD_FLAGS} ./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 . -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 + +# find or download ginkgo +# download ginkgo if necessary +ginkgo: +ifeq (, $(shell which ginkgo)) + @{ \ + set -e ;\ + go get github.com/onsi/ginkgo/ginkgo@v1.11.0 ;\ + } +GINKGO=$(GOBIN)/ginkgo +else +GINKGO=$(shell which ginkgo) +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 0000000000..80adfdc736 --- /dev/null +++ b/PROJECT @@ -0,0 +1,10 @@ +domain: opentelemetry.io +layout: go.kubebuilder.io/v2 +repo: github.com/open-telemetry/opentelemetry-operator +resources: +- group: core + kind: OpenTelemetryCollector + version: v1alpha1 +version: 3-alpha +plugins: + go.operator-sdk.io/v2-alpha: {} diff --git a/README.md b/README.md index b932295fa4..76a42d09fb 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,13 @@ The OpenTelemetry Operator is an implementation of a [Kubernetes Operator](https://coreos.com/operators/). -At this point, it has [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-service) as the only managed component. +At this point, it has [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) as the only managed component. ## Getting started -To install the operator, run: +To run the operator locally, run: ``` -kubectl create -f https://raw.githubusercontent.com/open-telemetry/opentelemetry-operator/master/deploy/crds/opentelemetry.io_opentelemetrycollectors_crd.yaml -kubectl create -f https://raw.githubusercontent.com/open-telemetry/opentelemetry-operator/master/deploy/service_account.yaml -kubectl create -f https://raw.githubusercontent.com/open-telemetry/opentelemetry-operator/master/deploy/role.yaml -kubectl create -f https://raw.githubusercontent.com/open-telemetry/opentelemetry-operator/master/deploy/role_binding.yaml -kubectl create -f https://raw.githubusercontent.com/open-telemetry/opentelemetry-operator/master/deploy/operator.yaml +make install run ``` Once the `opentelemetry-operator` deployment is ready, create an OpenTelemetry Collector (otelcol) instance, like: @@ -27,7 +23,6 @@ kind: OpenTelemetryCollector metadata: name: simplest spec: - image: otel/opentelemetry-collector:latest config: | receivers: jaeger: @@ -52,7 +47,7 @@ compatible with the latest version of the OpenTelemetry Collector image being re This will create an OpenTelemetry Collector instance named `simplest`, exposing a `jaeger-grpc` port to consume spans from your instrumented applications and exporting those spans via `logging`, which writes the spans to the console (`stdout`) of the OpenTelemetry Collector instance that receives the span. -The `config` node holds the `YAML` that should be passed down as-is to the underlying OpenTelemetry Collector instances. Refer to the [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-service) documentation for a reference of the possible entries. +The `config` node holds the `YAML` that should be passed down as-is to the underlying OpenTelemetry Collector instances. Refer to the [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) documentation for a reference of the possible entries. At this point, the Operator does *not* validate the contents of the configuration file: if the configuration is invalid, the instance will still be created but the underlying OpenTelemetry Collector might crash. @@ -60,30 +55,18 @@ At this point, the Operator does *not* validate the contents of the configuratio The `CustomResource` for the `OpenTelemetryCollector` exposes a property named `.Spec.Mode`, which can be used to specify whether the collector should run as a `DaemonSet` or as a `Deployment` (default). Look at the `examples/daemonset.yaml` for reference. -## Prometheus ServiceMonitor objects - -When the Prometheus Operator is available in the same cluster as the OpenTelemetry Operator, the OpenTelemetry Operator will automatically create the relevant `ServiceMonitor` objects: +## Contributing and Developing -* One set for the OpenTelemetry Operator itself -* One set for each managed OpenTelemetry instance +Please see [CONTRIBUTING.md](CONTRIBUTING.md). -Refer to the Prometheus Operator for complete instructions on how to do a production-quality installation. For development purposes, the following will do: +## Testing -```console -$ kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/v0.33.0/bundle.yaml +With an existing cluster (such as `minikube`), run: ``` - -When deploying the example `simplest.yaml`, the following `ServiceMonitor` will be created once the Prometheus Operator is available: - -```console -$ kubectl get servicemonitors simplest-collector -NAME AGE -simplest-collector 103s +USE_EXISTING_CLUSTER=true make test ``` -## Contributing and Developing - -Please see [CONTRIBUTING.md](CONTRIBUTING.md). +Tests can also be run without an existing cluster. For that, install [`kubebuilder`](https://book.kubebuilder.io/quick-start.html#installation). In this case, the tests will bootstrap `etcd` and `kubernetes-api-server` for the tests. Run against an existing cluster whenever possible, though. ## License diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go new file mode 100644 index 0000000000..a04f53bb5f --- /dev/null +++ b/api/v1alpha1/groupversion_info.go @@ -0,0 +1,34 @@ +// Copyright The OpenTelemetry Authors +// +// 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 core v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=opentelemetry.io +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "opentelemetry.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/api/v1alpha1/mode.go b/api/v1alpha1/mode.go new file mode 100644 index 0000000000..6d896161fc --- /dev/null +++ b/api/v1alpha1/mode.go @@ -0,0 +1,29 @@ +// Copyright The OpenTelemetry Authors +// +// 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 + +type ( + // Mode represents how the collector should be deployed (deployment vs. daemonset) + // +kubebuilder:validation:Enum=daemonset;deployment + Mode string +) + +const ( + // ModeDaemonSet specifies that the collector should be deployed as a Kubernetes DaemonSet + ModeDaemonSet Mode = "daemonset" + + // ModeDeployment specifies that the collector should be deployed as a Kubernetes Deployment + ModeDeployment Mode = "deployment" +) diff --git a/pkg/apis/opentelemetry/v1alpha1/opentelemetrycollector_types.go b/api/v1alpha1/opentelemetrycollector_types.go similarity index 83% rename from pkg/apis/opentelemetry/v1alpha1/opentelemetrycollector_types.go rename to api/v1alpha1/opentelemetrycollector_types.go index b75e1a0e48..4f5bd144e6 100644 --- a/pkg/apis/opentelemetry/v1alpha1/opentelemetrycollector_types.go +++ b/api/v1alpha1/opentelemetrycollector_types.go @@ -1,14 +1,25 @@ +// Copyright The OpenTelemetry Authors +// +// 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 import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" ) // OpenTelemetryCollectorSpec defines the desired state of OpenTelemetryCollector -// +k8s:openapi-gen=true type OpenTelemetryCollectorSpec struct { // Config is the raw JSON to be used as the collector's configuration. Refer to the OpenTelemetry Collector documentation for details. // +required @@ -34,7 +45,7 @@ type OpenTelemetryCollectorSpec struct { // +optional // +kubebuilder:validation:Enum=daemonset;deployment // +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true - Mode opentelemetry.Mode `json:"mode,omitempty"` + Mode Mode `json:"mode,omitempty"` // ServiceAccount indicates the name of an existing service account to use with this instance. // +optional @@ -63,21 +74,17 @@ type OpenTelemetryCollectorSpec struct { } // OpenTelemetryCollectorStatus defines the observed state of OpenTelemetryCollector -// +k8s:openapi-gen=true type OpenTelemetryCollectorStatus struct { Replicas int32 `json:"replicas"` Version string `json:"version"` } -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -// OpenTelemetryCollector is the Schema for the opentelemetrycollectors API -// +k8s:openapi-gen=true +// +kubebuilder:object:root=true // +kubebuilder:resource:shortName=otelcol;otelcols // +kubebuilder:subresource:status // +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas -// +genclient -// +operator-sdk:gen-csv:customresourcedefinitions.displayName="OpenTelemetry Collector" + +// OpenTelemetryCollector is the Schema for the opentelemetrycollectors API type OpenTelemetryCollector struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -86,7 +93,7 @@ type OpenTelemetryCollector struct { Status OpenTelemetryCollectorStatus `json:"status,omitempty"` } -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true // OpenTelemetryCollectorList contains a list of OpenTelemetryCollector type OpenTelemetryCollectorList struct { @@ -98,6 +105,3 @@ type OpenTelemetryCollectorList struct { func init() { SchemeBuilder.Register(&OpenTelemetryCollector{}, &OpenTelemetryCollectorList{}) } - -// AddToScheme is an alias to SchemeBuilder.AddToScheme, to please client-gen -var AddToScheme = SchemeBuilder.AddToScheme diff --git a/pkg/apis/opentelemetry/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go similarity index 85% rename from pkg/apis/opentelemetry/v1alpha1/zz_generated.deepcopy.go rename to api/v1alpha1/zz_generated.deepcopy.go index 153f0e1ce3..9d2237d9ee 100644 --- a/pkg/apis/opentelemetry/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,11 +1,25 @@ // +build !ignore_autogenerated -// Code generated by operator-sdk. DO NOT EDIT. +// Copyright The OpenTelemetry Authors +// +// 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 ( - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -16,7 +30,6 @@ func (in *OpenTelemetryCollector) DeepCopyInto(out *OpenTelemetryCollector) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryCollector. @@ -49,7 +62,6 @@ func (in *OpenTelemetryCollectorList) DeepCopyInto(out *OpenTelemetryCollectorLi (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryCollectorList. @@ -106,7 +118,6 @@ func (in *OpenTelemetryCollectorSpec) DeepCopyInto(out *OpenTelemetryCollectorSp (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryCollectorSpec. @@ -122,7 +133,6 @@ func (in *OpenTelemetryCollectorSpec) DeepCopy() *OpenTelemetryCollectorSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenTelemetryCollectorStatus) DeepCopyInto(out *OpenTelemetryCollectorStatus) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenTelemetryCollectorStatus. diff --git a/build/Dockerfile b/build/Dockerfile deleted file mode 100644 index 32e2fb838e..0000000000 --- a/build/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM registry.access.redhat.com/ubi8/ubi-minimal:latest - -ENV OPERATOR=/usr/local/bin/opentelemetry-operator \ - USER_UID=1001 \ - USER_NAME=opentelemetry-operator - -# install operator binary -COPY build/_output/bin/opentelemetry-operator ${OPERATOR} - -ENTRYPOINT [${OPERATOR}] - -USER ${USER_UID} diff --git a/cmd/manager/empty_test.go b/cmd/manager/empty_test.go deleted file mode 100644 index f69931bba6..0000000000 --- a/cmd/manager/empty_test.go +++ /dev/null @@ -1,2 +0,0 @@ -// this file exists to force the coverage tool to count this directory -package main diff --git a/cmd/manager/main.go b/cmd/manager/main.go deleted file mode 100644 index ea752dc53a..0000000000 --- a/cmd/manager/main.go +++ /dev/null @@ -1,235 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "os" - "runtime" - "strings" - - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - _ "k8s.io/client-go/plugin/pkg/client/auth" - "k8s.io/client-go/rest" - - "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" - "github.com/spf13/pflag" - "github.com/spf13/viper" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/util/intstr" - "sigs.k8s.io/controller-runtime/pkg/cache" - "sigs.k8s.io/controller-runtime/pkg/client/config" - "sigs.k8s.io/controller-runtime/pkg/manager" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - "sigs.k8s.io/controller-runtime/pkg/runtime/signals" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - "github.com/open-telemetry/opentelemetry-operator/pkg/controller" - "github.com/open-telemetry/opentelemetry-operator/pkg/upgrade" - "github.com/open-telemetry/opentelemetry-operator/pkg/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() { - v := version.Get() - log.Info("Starting the OpenTelemetry Operator", - "opentelemetry-operator", v.Operator, - "opentelemetry-collector", v.OpenTelemetryCollector, - "build-date", v.BuildDate, - "go-version", v.Go, - "go-arch", runtime.GOARCH, - "go-os", runtime.GOOS, - "operator-sdk-version", v.OperatorSdk, - ) -} - -func main() { - ctx := context.Background() - - // 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) - - // Add flags related to this operator - pflag.CommandLine.AddFlagSet(opentelemetry.FlagSet()) - - 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() - - 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) - } - - // Become the leader before proceeding - err = leader.Become(ctx, "opentelemetry-operator-lock") - if err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Create a new Cmd to provide shared dependencies and start components - 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, ",")) - } - - // 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 client set - if cl, err := client.ForManager(mgr); err == nil { - ctxUpgrade := context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("upgrade_opentelemetrycollector")) - if err := upgrade.ManagedInstances(ctxUpgrade, cl); err != nil { - log.Error(err, "failed to upgrade managed instances") - } - } else { - log.Error(err, "failed to obtain a set of clients to perform the upgrade") - } - - // Setup all Controllers - if err := controller.AddToManager(mgr); err != nil { - log.Error(err, "") - os.Exit(1) - } - - // Add the Metrics Service - addMetrics(ctx, cfg) - - // Start the Cmd - if err := mgr.Start(signals.SetupSignalHandler()); 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 - svcMonitorAvail := true - _, 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 { - svcMonitorAvail = false - log.Info("Install prometheus-operator in your cluster to create ServiceMonitor objects", "error", err.Error()) - } - } - viper.Set(opentelemetry.SvcMonitorAvailable, svcMonitorAvail) -} - -// 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/certmanager/certificate.yaml b/config/certmanager/certificate.yaml new file mode 100644 index 0000000000..58db114fa0 --- /dev/null +++ b/config/certmanager/certificate.yaml @@ -0,0 +1,26 @@ +# The following manifests contain a self-signed issuer CR and a certificate CR. +# More document can be found at https://docs.cert-manager.io +# WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for +# breaking changes +apiVersion: cert-manager.io/v1alpha2 +kind: Issuer +metadata: + name: selfsigned-issuer + namespace: system +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1alpha2 +kind: Certificate +metadata: + name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml + namespace: system +spec: + # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize + dnsNames: + - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc + - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local + issuerRef: + kind: Issuer + name: selfsigned-issuer + secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize diff --git a/config/certmanager/kustomization.yaml b/config/certmanager/kustomization.yaml new file mode 100644 index 0000000000..bebea5a595 --- /dev/null +++ b/config/certmanager/kustomization.yaml @@ -0,0 +1,5 @@ +resources: +- certificate.yaml + +configurations: +- kustomizeconfig.yaml diff --git a/config/certmanager/kustomizeconfig.yaml b/config/certmanager/kustomizeconfig.yaml new file mode 100644 index 0000000000..90d7c313ca --- /dev/null +++ b/config/certmanager/kustomizeconfig.yaml @@ -0,0 +1,16 @@ +# This configuration is for teaching kustomize how to update name ref and var substitution +nameReference: +- kind: Issuer + group: cert-manager.io + fieldSpecs: + - kind: Certificate + group: cert-manager.io + path: spec/issuerRef/name + +varReference: +- kind: Certificate + group: cert-manager.io + path: spec/commonName +- kind: Certificate + group: cert-manager.io + path: spec/dnsNames diff --git a/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml new file mode 100644 index 0000000000..1b08c7821d --- /dev/null +++ b/config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml @@ -0,0 +1,1396 @@ + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: opentelemetrycollectors.opentelemetry.io +spec: + group: opentelemetry.io + names: + kind: OpenTelemetryCollector + listKind: OpenTelemetryCollectorList + plural: opentelemetrycollectors + shortNames: + - otelcol + - otelcols + singular: opentelemetrycollector + scope: Namespaced + subresources: + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas + status: {} + validation: + openAPIV3Schema: + description: OpenTelemetryCollector is the Schema for the opentelemetrycollectors + 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: OpenTelemetryCollectorSpec defines the desired state of OpenTelemetryCollector + properties: + args: + additionalProperties: + type: string + description: Args is the set of arguments to pass to the OpenTelemetry + Collector binary + type: object + config: + description: Config is the raw JSON to be used as the collector's configuration. + Refer to the OpenTelemetry Collector documentation for details. + type: string + image: + description: Image indicates the container image to use for the OpenTelemetry + Collector. + type: string + mode: + allOf: + - enum: + - daemonset + - deployment + - enum: + - daemonset + - deployment + description: Mode represents how the collector should be deployed (deployment + vs. daemonset) + type: string + ports: + description: Ports allows a set of ports to be exposed by the underlying + v1.Service. By default, the operator will attempt to infer the required + ports by parsing the .Spec.Config property but this property can be + used to open aditional ports that can't be inferred by the operator, + like for custom receivers. + items: + description: ServicePort contains information on service's port. + properties: + appProtocol: + description: The application protocol for this port. This field + follows standard Kubernetes label syntax. Un-prefixed names + are reserved for IANA standard service names (as per RFC-6335 + and http://www.iana.org/assignments/service-names). Non-standard + protocols should use prefixed names such as mycompany.com/my-custom-protocol. + Field can be enabled with ServiceAppProtocol feature gate. + type: string + name: + description: The name of this port within the service. This must + be a DNS_LABEL. All ports within a ServiceSpec must have unique + names. When considering the endpoints for a Service, this must + match the 'name' field in the EndpointPort. Optional if only + one ServicePort is defined on this service. + type: string + nodePort: + description: 'The port on each node on which this service is exposed + when type=NodePort or LoadBalancer. Usually assigned by the + system. If specified, it will be allocated to the service if + unused or else creation of the service will fail. Default is + to auto-allocate a port if the ServiceType of this Service requires + one. More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport' + format: int32 + type: integer + port: + description: The port that will be exposed by this service. + format: int32 + type: integer + protocol: + description: The IP protocol for this port. Supports "TCP", "UDP", + and "SCTP". Default is TCP. + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: 'Number or name of the port to access on the pods + targeted by the service. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. If this is a string, it will + be looked up as a named port in the target Pod''s container + ports. If this is not specified, the value of the ''port'' field + is used (an identity map). This field is ignored for services + with clusterIP=None, and should be omitted or set equal to the + ''port'' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service' + x-kubernetes-int-or-string: true + required: + - port + type: object + type: array + x-kubernetes-list-type: atomic + replicas: + description: Replicas is the number of pod instances for the underlying + OpenTelemetry Collector + format: int32 + type: integer + serviceAccount: + description: ServiceAccount indicates the name of an existing service + account to use with this instance. + type: string + volumeMounts: + description: VolumeMounts represents the mount points to use in the + underlying collector deployment(s) + items: + description: VolumeMount describes a mounting of a Volume within a + container. + properties: + mountPath: + description: Path within the container at which the volume should + be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are propagated + from the host to container and the other way around. When not + set, MountPropagationNone is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise (false + or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which the container's + volume should be mounted. Behaves similarly to SubPath but environment + variable references $(VAR_NAME) are expanded using the container's + environment. Defaults to "" (volume's root). SubPathExpr and + SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-type: atomic + volumes: + description: Volumes represents which volumes to use in the underlying + collector deployment(s). + items: + description: Volume represents a named volume in a pod that may be + accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'AWSElasticBlockStore represents an AWS Disk resource + that is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'Filesystem type of the volume that you want + to mount. Tip: Ensure that the filesystem type is supported + by the host operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from compromising + the machine' + type: string + partition: + description: 'The partition in the volume that you want to + mount. If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for /dev/sda is + "0" (or you can leave the property empty).' + format: int32 + type: integer + readOnly: + description: 'Specify "true" to force and set the ReadOnly + property in VolumeMounts to "true". If omitted, the default + is "false". More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'Unique ID of the persistent disk resource in + AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: AzureDisk represents an Azure Data Disk mount on + the host and bind mount to the pod. + properties: + cachingMode: + description: 'Host Caching mode: None, Read Only, Read Write.' + type: string + diskName: + description: The Name of the data disk in the blob storage + type: string + diskURI: + description: The URI the data disk in the blob storage + type: string + fsType: + description: Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'Expected values Shared: multiple blob disks + per storage account Dedicated: single blob disk per storage + account Managed: azure managed data disk (only in managed + availability set). defaults to shared' + type: string + readOnly: + description: Defaults to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: AzureFile represents an Azure File Service mount + on the host and bind mount to the pod. + properties: + readOnly: + description: Defaults to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: the name of secret that contains Azure Storage + Account Name and Key + type: string + shareName: + description: Share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: CephFS represents a Ceph FS mount on the host that + shares a pod's lifetime + properties: + monitors: + description: 'Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'Optional: Used as the mounted root, rather than + the full Ceph tree, default is /' + type: string + readOnly: + description: 'Optional: Defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. More + info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'Optional: SecretFile is the path to key ring + for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'Optional: SecretRef is reference to the authentication + secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + user: + description: 'Optional: User is the rados user name, default + is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'Cinder represents a cinder volume attached and mounted + on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'Optional: Defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts. More + info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'Optional: points to a secret object containing + parameters used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + volumeID: + description: 'volume id used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: ConfigMap represents a configMap that should populate + this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created files + by default. Must be a value between 0 and 0777. Defaults + to 0644. Directories within the path are not affected by + this setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: If unspecified, each key-value pair in the Data + field of the referenced ConfigMap will be projected into + the volume as a file whose name is the key and content is + the value. If specified, the listed keys will be projected + into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the + ConfigMap, the volume setup will error unless it is marked + optional. Paths must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits to use on this file, + must be a value between 0 and 0777. If not specified, + the volume defaultMode will be used. This might be + in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: The relative path of the file to map the + key to. May not be an absolute path. May not contain + the path element '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its keys must + be defined + type: boolean + type: object + csi: + description: CSI (Container Storage Interface) represents storage + that is handled by an external CSI driver (Alpha feature). + properties: + driver: + description: Driver is the name of the CSI driver that handles + this volume. Consult with your admin for the correct name + as registered in the cluster. + type: string + fsType: + description: Filesystem type to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is passed to the + associated CSI driver which will determine the default filesystem + to apply. + type: string + nodePublishSecretRef: + description: NodePublishSecretRef is a reference to the secret + object containing sensitive information to pass to the CSI + driver to complete the CSI NodePublishVolume and NodeUnpublishVolume + calls. This field is optional, and may be empty if no secret + is required. If the secret object contains more than one + secret, all secret references are passed. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + readOnly: + description: Specifies a read-only configuration for the volume. + Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: VolumeAttributes stores driver-specific properties + that are passed to the CSI driver. Consult your driver's + documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: DownwardAPI represents downward API about the pod + that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created files + by default. Must be a value between 0 and 0777. Defaults + to 0644. Directories within the path are not affected by + this setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the pod: + only annotations, labels, name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + mode: + description: 'Optional: mode bits to use on this file, + must be a value between 0 and 0777. If not specified, + the volume defaultMode will be used. This might be + in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative path name + of the file to be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 encoded. The + first item of the relative path must not start with + ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'EmptyDir represents a temporary directory that shares + a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'What type of storage medium should back this + directory. The default is "" which means to use the node''s + default medium. Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'Total amount of local storage required for this + EmptyDir volume. The size limit is also applicable for memory + medium. The maximum usage on memory medium EmptyDir would + be the minimum value between the SizeLimit specified here + and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + fc: + description: FC represents a Fibre Channel resource that is attached + to a kubelet's host machine and then exposed to the pod. + properties: + fsType: + description: 'Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the filesystem from compromising + the machine' + type: string + lun: + description: 'Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'Optional: Defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'Optional: FC target worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be + set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: FlexVolume represents a generic volume resource that + is provisioned/attached using an exec based plugin. + properties: + driver: + description: Driver is the name of the driver to use for this + volume. + type: string + fsType: + description: Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Ex. "ext4", + "xfs", "ntfs". The default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'Optional: Extra command options if any.' + type: object + readOnly: + description: 'Optional: Defaults to false (read/write). ReadOnly + here will force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'Optional: SecretRef is reference to the secret + object containing sensitive information to pass to the plugin + scripts. This may be empty if no secret object is specified. + If the secret object contains more than one secret, all + secrets are passed to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + required: + - driver + type: object + flocker: + description: Flocker represents a Flocker volume attached to a + kubelet's host machine. This depends on the Flocker control + service being running + properties: + datasetName: + description: Name of the dataset stored as metadata -> name + on the dataset for Flocker should be considered as deprecated + type: string + datasetUUID: + description: UUID of the dataset. This is unique identifier + of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'GCEPersistentDisk represents a GCE Disk resource + that is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'Filesystem type of the volume that you want + to mount. Tip: Ensure that the filesystem type is supported + by the host operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from compromising + the machine' + type: string + partition: + description: 'The partition in the volume that you want to + mount. If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for /dev/sda is + "0" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'Unique name of the PD resource in GCE. Used + to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'ReadOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'GitRepo represents a git repository at a particular + revision. DEPRECATED: GitRepo is deprecated. To provision a + container with a git repo, mount an EmptyDir into an InitContainer + that clones the repo using git, then mount the EmptyDir into + the Pod''s container.' + properties: + directory: + description: Target directory name. Must not contain or start + with '..'. If '.' is supplied, the volume directory will + be the git repository. Otherwise, if specified, the volume + will contain the git repository in the subdirectory with + the given name. + type: string + repository: + description: Repository URL + type: string + revision: + description: Commit hash for the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'Glusterfs represents a Glusterfs mount on the host + that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'EndpointsName is the endpoint name that details + Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'Path is the Glusterfs volume path. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'ReadOnly here will force the Glusterfs volume + to be mounted with read-only permissions. Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'HostPath represents a pre-existing file or directory + on the host machine that is directly exposed to the container. + This is generally used for system agents or other privileged + things that are allowed to see the host machine. Most containers + will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use host directory + mounts and who can/can not mount host directories as read/write.' + properties: + path: + description: 'Path of the directory on the host. If the path + is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'Type for HostPath Volume Defaults to "" More + info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'ISCSI represents an ISCSI Disk resource that is + attached to a kubelet''s host machine and then exposed to the + pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: whether support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: whether support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'Filesystem type of the volume that you want + to mount. Tip: Ensure that the filesystem type is supported + by the host operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from compromising + the machine' + type: string + initiatorName: + description: Custom iSCSI Initiator Name. If initiatorName + is specified with iscsiInterface simultaneously, new iSCSI + interface : will be created + for the connection. + type: string + iqn: + description: Target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iSCSI Interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). + type: string + lun: + description: iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: iSCSI Target Portal List. The portal is either + an IP or ip_addr:port if the port is other than default + (typically TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: ReadOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: CHAP Secret for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + targetPortal: + description: iSCSI Target Portal. The Portal is either an + IP or ip_addr:port if the port is other than default (typically + TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'Volume''s name. Must be a DNS_LABEL and unique within + the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'NFS represents an NFS mount on the host that shares + a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'Path that is exported by the NFS server. More + info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'ReadOnly here will force the NFS export to be + mounted with read-only permissions. Defaults to false. More + info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'Server is the hostname or IP address of the + NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'PersistentVolumeClaimVolumeSource represents a reference + to a PersistentVolumeClaim in the same namespace. More info: + https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'ClaimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: Will force the ReadOnly setting in VolumeMounts. + Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: PhotonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host machine + properties: + fsType: + description: Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: ID that identifies Photon Controller persistent + disk + type: string + required: + - pdID + type: object + portworxVolume: + description: PortworxVolume represents a portworx volume attached + and mounted on kubelets host machine + properties: + fsType: + description: FSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" + if unspecified. + type: string + readOnly: + description: Defaults to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: VolumeID uniquely identifies a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: Items for all in one resources secrets, configmaps, + and downward API + properties: + defaultMode: + description: Mode bits to use on created files by default. + Must be a value between 0 and 0777. Directories within the + path are not affected by this setting. This might be in + conflict with other options that affect the file mode, like + fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: list of volume projections + items: + description: Projection that may be projected along with + other supported volume types + properties: + configMap: + description: information about the configMap data to + project + properties: + items: + description: If unspecified, each key-value pair + in the Data field of the referenced ConfigMap + will be projected into the volume as a file whose + name is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. + If a key is specified which is not present in + the ConfigMap, the volume setup will error unless + it is marked optional. Paths must be relative + and may not contain the '..' path or start with + '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits to use on + this file, must be a value between 0 and + 0777. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: The relative path of the file + to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + keys must be defined + type: boolean + type: object + downwardAPI: + description: information about the downwardAPI data + to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing the + pod field + properties: + fieldRef: + description: 'Required: Selects a field of + the pod: only annotations, labels, name + and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + mode: + description: 'Optional: mode bits to use on + this file, must be a value between 0 and + 0777. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' path. + Must be utf-8 encoded. The first item of + the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults to + "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + required: + - path + type: object + type: array + type: object + secret: + description: information about the secret data to project + properties: + items: + description: If unspecified, each key-value pair + in the Data field of the referenced Secret will + be projected into the volume as a file whose name + is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. + If a key is specified which is not present in + the Secret, the volume setup will error unless + it is marked optional. Paths must be relative + and may not contain the '..' path or start with + '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits to use on + this file, must be a value between 0 and + 0777. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: The relative path of the file + to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + type: object + serviceAccountToken: + description: information about the serviceAccountToken + data to project + properties: + audience: + description: Audience is the intended audience of + the token. A recipient of a token must identify + itself with an identifier specified in the audience + of the token, and otherwise should reject the + token. The audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: ExpirationSeconds is the requested + duration of validity of the service account token. + As the token approaches expiration, the kubelet + volume plugin will proactively rotate the service + account token. The kubelet will start trying to + rotate the token if the token is older than 80 + percent of its time to live or if the token is + older than 24 hours.Defaults to 1 hour and must + be at least 10 minutes. + format: int64 + type: integer + path: + description: Path is the path relative to the mount + point of the file to project the token into. + type: string + required: + - path + type: object + type: object + type: array + required: + - sources + type: object + quobyte: + description: Quobyte represents a Quobyte mount on the host that + shares a pod's lifetime + properties: + group: + description: Group to map volume access to Default is no group + type: string + readOnly: + description: ReadOnly here will force the Quobyte volume to + be mounted with read-only permissions. Defaults to false. + type: boolean + registry: + description: Registry represents a single or multiple Quobyte + Registry services specified as a string as host:port pair + (multiple entries are separated with commas) which acts + as the central registry for volumes + type: string + tenant: + description: Tenant owning the given Quobyte volume in the + Backend Used with dynamically provisioned Quobyte volumes, + value is set by the plugin + type: string + user: + description: User to map volume access to Defaults to serivceaccount + user + type: string + volume: + description: Volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'RBD represents a Rados Block Device mount on the + host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'Filesystem type of the volume that you want + to mount. Tip: Ensure that the filesystem type is supported + by the host operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from compromising + the machine' + type: string + image: + description: 'The rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'Keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'A collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'The rados pool name. Default is rbd. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'ReadOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'SecretRef is name of the authentication secret + for RBDUser. If provided overrides keyring. Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + user: + description: 'The rados user name. Default is admin. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: ScaleIO represents a ScaleIO persistent volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Ex. "ext4", + "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: The host address of the ScaleIO API Gateway. + type: string + protectionDomain: + description: The name of the ScaleIO Protection Domain for + the configured storage. + type: string + readOnly: + description: Defaults to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: SecretRef references to the secret for ScaleIO + user and other sensitive information. If this is not provided, + Login operation will fail. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + sslEnabled: + description: Flag to enable/disable SSL communication with + Gateway, default false + type: boolean + storageMode: + description: Indicates whether the storage for a volume should + be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: The ScaleIO Storage Pool associated with the + protection domain. + type: string + system: + description: The name of the storage system as configured + in ScaleIO. + type: string + volumeName: + description: The name of a volume already created in the ScaleIO + system that is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'Secret represents a secret that should populate + this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'Optional: mode bits to use on created files + by default. Must be a value between 0 and 0777. Defaults + to 0644. Directories within the path are not affected by + this setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: If unspecified, each key-value pair in the Data + field of the referenced Secret will be projected into the + volume as a file whose name is the key and content is the + value. If specified, the listed keys will be projected into + the specified paths, and unlisted keys will not be present. + If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' path + or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: The key to project. + type: string + mode: + description: 'Optional: mode bits to use on this file, + must be a value between 0 and 0777. If not specified, + the volume defaultMode will be used. This might be + in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: The relative path of the file to map the + key to. May not be an absolute path. May not contain + the path element '..'. May not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: Specify whether the Secret or its keys must be + defined + type: boolean + secretName: + description: 'Name of the secret in the pod''s namespace to + use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: StorageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: Defaults to false (read/write). ReadOnly here + will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: SecretRef specifies the secret to use for obtaining + the StorageOS API credentials. If not specified, default + values will be attempted. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + volumeName: + description: VolumeName is the human-readable name of the + StorageOS volume. Volume names are only unique within a + namespace. + type: string + volumeNamespace: + description: VolumeNamespace specifies the scope of the volume + within StorageOS. If no namespace is specified then the + Pod's namespace will be used. This allows the Kubernetes + name scoping to be mirrored within StorageOS for tighter + integration. Set VolumeName to any name to override the + default behaviour. Set to "default" if you are not using + namespaces within StorageOS. Namespaces that do not pre-exist + within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: VsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: Filesystem type to mount. Must be a filesystem + type supported by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: Storage Policy Based Management (SPBM) profile + ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: Storage Policy Based Management (SPBM) profile + name. + type: string + volumePath: + description: Path that identifies vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + x-kubernetes-list-type: atomic + type: object + status: + description: OpenTelemetryCollectorStatus defines the observed state of + OpenTelemetryCollector + properties: + replicas: + format: int32 + type: integer + version: + type: string + required: + - replicas + - version + 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 0000000000..3daa9acd22 --- /dev/null +++ b/config/crd/kustomization.yaml @@ -0,0 +1,21 @@ +# 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/opentelemetry.io_opentelemetrycollectors.yaml +# +kubebuilder:scaffold:crdkustomizeresource + +patchesStrategicMerge: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +#- patches/webhook_in_opentelemetrycollectors.yaml +# +kubebuilder:scaffold:crdkustomizewebhookpatch + +# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. +# patches here are for enabling the CA injection for each CRD +#- patches/cainjection_in_opentelemetrycollectors.yaml +# +kubebuilder:scaffold:crdkustomizecainjectionpatch + +# 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 0000000000..6f83d9a94b --- /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/crd/patches/cainjection_in_opentelemetrycollectors.yaml b/config/crd/patches/cainjection_in_opentelemetrycollectors.yaml new file mode 100644 index 0000000000..7b7d2f65f7 --- /dev/null +++ b/config/crd/patches/cainjection_in_opentelemetrycollectors.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: opentelemetrycollectors.opentelemetry.io diff --git a/config/crd/patches/webhook_in_opentelemetrycollectors.yaml b/config/crd/patches/webhook_in_opentelemetrycollectors.yaml new file mode 100644 index 0000000000..a04a64f791 --- /dev/null +++ b/config/crd/patches/webhook_in_opentelemetrycollectors.yaml @@ -0,0 +1,17 @@ +# The following patch enables conversion webhook for CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: opentelemetrycollectors.opentelemetry.io +spec: + conversion: + strategy: Webhook + webhookClientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml new file mode 100644 index 0000000000..89a6a85981 --- /dev/null +++ b/config/default/kustomization.yaml @@ -0,0 +1,70 @@ +# Adds namespace to all resources. +namespace: opentelemetry-operator-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: opentelemetry-operator- + +# Labels to add to all resources and selectors. +#commonLabels: +# someName: someValue + +bases: +- ../crd +- ../rbac +- ../manager +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- ../webhook +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. +#- ../certmanager +# [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 + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- manager_webhook_patch.yaml + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. +# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. +# 'CERTMANAGER' needs to be enabled to use ca injection +#- webhookcainjection_patch.yaml + +# the following config is for teaching kustomize how to do var substitution +vars: +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. +#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR +# objref: +# kind: Certificate +# group: cert-manager.io +# version: v1alpha2 +# name: serving-cert # this name should match the one in certificate.yaml +# fieldref: +# fieldpath: metadata.namespace +#- name: CERTIFICATE_NAME +# objref: +# kind: Certificate +# group: cert-manager.io +# version: v1alpha2 +# name: serving-cert # this name should match the one in certificate.yaml +#- name: SERVICE_NAMESPACE # namespace of the service +# objref: +# kind: Service +# version: v1 +# name: webhook-service +# fieldref: +# fieldpath: metadata.namespace +#- name: SERVICE_NAME +# objref: +# kind: Service +# version: v1 +# name: webhook-service diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 0000000000..77e743d1c1 --- /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 0000000000..738de350b7 --- /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: webhook-server-cert diff --git a/config/default/webhookcainjection_patch.yaml b/config/default/webhookcainjection_patch.yaml new file mode 100644 index 0000000000..7e79bf9955 --- /dev/null +++ b/config/default/webhookcainjection_patch.yaml @@ -0,0 +1,15 @@ +# This patch add annotation to admission webhook config and +# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +metadata: + name: mutating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml new file mode 100644 index 0000000000..5c5f0b84cb --- /dev/null +++ b/config/manager/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- manager.yaml diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml new file mode 100644 index 0000000000..b6c85a52d5 --- /dev/null +++ b/config/manager/manager.yaml @@ -0,0 +1,39 @@ +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: controller:latest + name: manager + resources: + limits: + cpu: 100m + memory: 30Mi + requests: + cpu: 100m + memory: 20Mi + terminationGracePeriodSeconds: 10 diff --git a/config/prometheus/kustomization.yaml b/config/prometheus/kustomization.yaml new file mode 100644 index 0000000000..ed137168a1 --- /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 0000000000..9b8047b760 --- /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 0000000000..7d62534c5f --- /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 0000000000..618f5e4177 --- /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 0000000000..48ed1e4b85 --- /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 0000000000..6cf656be14 --- /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 0000000000..66c28338fe --- /dev/null +++ b/config/rbac/kustomization.yaml @@ -0,0 +1,12 @@ +resources: +- role.yaml +- role_binding.yaml +- leader_election_role.yaml +- leader_election_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/leader_election_role.yaml b/config/rbac/leader_election_role.yaml new file mode 100644 index 0000000000..7dc16c420e --- /dev/null +++ b/config/rbac/leader_election_role.yaml @@ -0,0 +1,33 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: leader-election-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps/status + verbs: + - get + - update + - patch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch diff --git a/deploy/role_binding.yaml b/config/rbac/leader_election_role_binding.yaml similarity index 61% rename from deploy/role_binding.yaml rename to config/rbac/leader_election_role_binding.yaml index 481eff9aff..eed16906f4 100644 --- a/deploy/role_binding.yaml +++ b/config/rbac/leader_election_role_binding.yaml @@ -1,11 +1,12 @@ -kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding metadata: - name: opentelemetry-operator -subjects: -- kind: ServiceAccount - name: opentelemetry-operator + name: leader-election-rolebinding roleRef: - kind: Role - name: opentelemetry-operator apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election-role +subjects: +- kind: ServiceAccount + name: default + namespace: system diff --git a/deploy/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry-operator.v0.2.0.clusterserviceversion.yaml b/config/rbac/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry-operator.v0.2.0.clusterserviceversion.yaml similarity index 100% rename from deploy/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry-operator.v0.2.0.clusterserviceversion.yaml rename to config/rbac/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry-operator.v0.2.0.clusterserviceversion.yaml diff --git a/deploy/crds/opentelemetry.io_opentelemetrycollectors_crd.yaml b/config/rbac/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry.io_opentelemetrycollectors_crd.yaml similarity index 100% rename from deploy/crds/opentelemetry.io_opentelemetrycollectors_crd.yaml rename to config/rbac/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry.io_opentelemetrycollectors_crd.yaml diff --git a/config/rbac/opentelemetrycollector_editor_role.yaml b/config/rbac/opentelemetrycollector_editor_role.yaml new file mode 100644 index 0000000000..ebc8e6a010 --- /dev/null +++ b/config/rbac/opentelemetrycollector_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit opentelemetrycollectors. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: opentelemetrycollector-editor-role +rules: +- apiGroups: + - opentelemetry.io + resources: + - opentelemetrycollectors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opentelemetry.io + resources: + - opentelemetrycollectors/status + verbs: + - get diff --git a/config/rbac/opentelemetrycollector_viewer_role.yaml b/config/rbac/opentelemetrycollector_viewer_role.yaml new file mode 100644 index 0000000000..4a76c71d15 --- /dev/null +++ b/config/rbac/opentelemetrycollector_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view opentelemetrycollectors. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: opentelemetrycollector-viewer-role +rules: +- apiGroups: + - opentelemetry.io + resources: + - opentelemetrycollectors + verbs: + - get + - list + - watch +- apiGroups: + - opentelemetry.io + resources: + - opentelemetrycollectors/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml new file mode 100644 index 0000000000..320b1eecec --- /dev/null +++ b/config/rbac/role.yaml @@ -0,0 +1,40 @@ + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: manager-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opentelemetry.io + resources: + - opentelemetrycollectors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - opentelemetry.io + resources: + - opentelemetrycollectors/status + verbs: + - get + - patch + - update diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml new file mode 100644 index 0000000000..8f2658702c --- /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: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: manager-role +subjects: +- kind: ServiceAccount + name: default + namespace: system diff --git a/examples/simplest.yaml b/config/samples/core_v1alpha1_opentelemetrycollector.yaml similarity index 81% rename from examples/simplest.yaml rename to config/samples/core_v1alpha1_opentelemetrycollector.yaml index e8f48fc482..1735fe3fcd 100644 --- a/examples/simplest.yaml +++ b/config/samples/core_v1alpha1_opentelemetrycollector.yaml @@ -1,12 +1,13 @@ apiVersion: opentelemetry.io/v1alpha1 kind: OpenTelemetryCollector metadata: - name: simplest + name: opentelemetrycollector-sample spec: config: | receivers: jaeger: - grpc: + protocols: + grpc: processors: queued_retry: diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml new file mode 100644 index 0000000000..864ff055ac --- /dev/null +++ b/config/samples/kustomization.yaml @@ -0,0 +1,3 @@ +## This file is auto-generated, do not modify ## +resources: +- core_v1alpha1_opentelemetrycollector.yaml diff --git a/config/webhook/kustomization.yaml b/config/webhook/kustomization.yaml new file mode 100644 index 0000000000..9cf26134e4 --- /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 0000000000..25e21e3c96 --- /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/service.yaml b/config/webhook/service.yaml new file mode 100644 index 0000000000..31e0f82959 --- /dev/null +++ b/config/webhook/service.yaml @@ -0,0 +1,12 @@ + +apiVersion: v1 +kind: Service +metadata: + name: webhook-service + namespace: system +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + control-plane: controller-manager diff --git a/controllers/opentelemetrycollector_controller.go b/controllers/opentelemetrycollector_controller.go new file mode 100644 index 0000000000..ae8350739b --- /dev/null +++ b/controllers/opentelemetrycollector_controller.go @@ -0,0 +1,156 @@ +// Copyright The OpenTelemetry Authors +// +// 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 ( + "context" + "fmt" + + "github.com/go-logr/logr" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/internal/config" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/reconcile" +) + +// OpenTelemetryCollectorReconciler reconciles a OpenTelemetryCollector object +type OpenTelemetryCollectorReconciler struct { + client.Client + log logr.Logger + scheme *runtime.Scheme + config config.Config + tasks []Task +} + +// Task represents a reconciliation task to be executed by the reconciler +type Task struct { + Name string + Do func(context.Context, reconcile.Params) error + BailOnError bool +} + +// Params is the set of options to build a new openTelemetryCollectorReconciler +type Params struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme + Config config.Config + Tasks []Task +} + +// NewReconciler creates a new reconciler for OpenTelemetryCollector objects +func NewReconciler(p Params) *OpenTelemetryCollectorReconciler { + if len(p.Tasks) == 0 { + p.Tasks = []Task{ + { + "config maps", + reconcile.ConfigMaps, + true, + }, + { + "service accounts", + reconcile.ServiceAccounts, + true, + }, + { + "services", + reconcile.Services, + true, + }, + { + "deployments", + reconcile.Deployments, + true, + }, + { + "daemon sets", + reconcile.DaemonSets, + true, + }, + } + } + + return &OpenTelemetryCollectorReconciler{ + Client: p.Client, + log: p.Log, + scheme: p.Scheme, + config: p.Config, + tasks: p.Tasks, + } +} + +// +kubebuilder:rbac:groups=opentelemetry.io,resources=opentelemetrycollectors,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=opentelemetry.io,resources=opentelemetrycollectors/status,verbs=get;update;patch +// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;patch;delete + +// Reconcile the current state of an OpenTelemetry collector resource with the desired state +func (r *OpenTelemetryCollectorReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { + ctx := context.Background() + log := r.log.WithValues("opentelemetrycollector", req.NamespacedName) + + var instance v1alpha1.OpenTelemetryCollector + if err := r.Get(ctx, req.NamespacedName, &instance); err != nil { + log.Error(err, "unable to fetch OpenTelemetryCollector") + // we'll ignore not-found errors, since they can't be fixed by an immediate + // requeue (we'll need to wait for a new notification), and we can get them + // on deleted requests. + return ctrl.Result{}, client.IgnoreNotFound(err) + } + + params := reconcile.Params{ + Config: r.config, + Client: r.Client, + Instance: instance, + Log: log, + Scheme: r.scheme, + } + + if err := r.RunTasks(ctx, params); err != nil { + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +// RunTasks runs all the tasks associated with this reconciler +func (r *OpenTelemetryCollectorReconciler) RunTasks(ctx context.Context, params reconcile.Params) error { + for _, task := range r.tasks { + if err := task.Do(ctx, params); err != nil { + r.log.Error(err, fmt.Sprintf("failed to reconcile %s", task.Name)) + if task.BailOnError { + return err + } + } + } + + return nil +} + +// SetupWithManager tells the manager what our controller is interested in +func (r *OpenTelemetryCollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.OpenTelemetryCollector{}). + Owns(&corev1.ConfigMap{}). + Owns(&corev1.ServiceAccount{}). + Owns(&corev1.Service{}). + Owns(&appsv1.Deployment{}). + Owns(&appsv1.DaemonSet{}). + Complete(r) +} diff --git a/controllers/opentelemetrycollector_controller_test.go b/controllers/opentelemetrycollector_controller_test.go new file mode 100644 index 0000000000..6f91380396 --- /dev/null +++ b/controllers/opentelemetrycollector_controller_test.go @@ -0,0 +1,229 @@ +package controllers_test + +import ( + "context" + "errors" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/kubectl/pkg/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + k8sconfig "sigs.k8s.io/controller-runtime/pkg/client/config" + "sigs.k8s.io/controller-runtime/pkg/manager" + k8sreconcile "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/controllers" + "github.com/open-telemetry/opentelemetry-operator/internal/config" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/reconcile" +) + +var _ = Describe("OpenTelemetryCollector controller", func() { + logger := logf.Log.WithName("unit-tests") + cfg := config.DefaultConfig() + cfg.FlagSet().Parse([]string{}) + + It("should generate the underlying objects on reconciliation", func() { + // prepare + nsn := types.NamespacedName{Name: "my-instance", Namespace: "default"} + reconciler := controllers.NewReconciler(controllers.Params{ + Client: k8sClient, + Log: logger, + Scheme: scheme.Scheme, + Config: cfg, + }) + created := &v1alpha1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: nsn.Name, + Namespace: nsn.Namespace, + }, + } + err := k8sClient.Create(context.Background(), created) + Expect(err).ToNot(HaveOccurred()) + + // test + req := k8sreconcile.Request{ + NamespacedName: nsn, + } + _, err = reconciler.Reconcile(req) + + // verify + Expect(err).ToNot(HaveOccurred()) + + // the base query for the underlying objects + opts := []client.ListOption{ + client.InNamespace(nsn.Namespace), + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", nsn.Namespace, nsn.Name), + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }), + } + + // verify that we have at least one object for each of the types we create + // whether we have the right ones is up to the specific tests for each type + { + list := &corev1.ConfigMapList{} + err = k8sClient.List(context.Background(), list, opts...) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).ToNot(BeEmpty()) + } + { + list := &corev1.ServiceAccountList{} + err = k8sClient.List(context.Background(), list, opts...) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).ToNot(BeEmpty()) + } + { + list := &corev1.ServiceList{} + err = k8sClient.List(context.Background(), list, opts...) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).ToNot(BeEmpty()) + } + { + list := &appsv1.DeploymentList{} + err = k8sClient.List(context.Background(), list, opts...) + Expect(err).ToNot(HaveOccurred()) + Expect(list.Items).ToNot(BeEmpty()) + } + { + list := &appsv1.DaemonSetList{} + err = k8sClient.List(context.Background(), list, opts...) + Expect(err).ToNot(HaveOccurred()) + // attention! we expect daemonsets to be empty in the default configuration + Expect(list.Items).To(BeEmpty()) + } + + // cleanup + Expect(k8sClient.Delete(context.Background(), created)).ToNot(HaveOccurred()) + }) + + It("should continue when a task's failure can be recovered", func() { + // prepare + taskCalled := false + reconciler := controllers.NewReconciler(controllers.Params{ + Log: logger, + Tasks: []controllers.Task{ + { + Name: "should-fail", + Do: func(context.Context, reconcile.Params) error { + return errors.New("should fail!") + }, + BailOnError: false, + }, + { + Name: "should-be-called", + Do: func(context.Context, reconcile.Params) error { + taskCalled = true + return nil + }, + }, + }, + }) + + // test + err := reconciler.RunTasks(context.Background(), reconcile.Params{}) + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(taskCalled).To(BeTrue()) + }) + + It("should not continue when a task's failure can't be recovered", func() { + // prepare + taskCalled := false + expectedErr := errors.New("should fail!") + nsn := types.NamespacedName{Name: "my-instance", Namespace: "default"} + reconciler := controllers.NewReconciler(controllers.Params{ + Client: k8sClient, + Log: logger, + Scheme: scheme.Scheme, + Config: cfg, + Tasks: []controllers.Task{ + { + Name: "should-fail", + Do: func(context.Context, reconcile.Params) error { + taskCalled = true + return expectedErr + }, + BailOnError: true, + }, + { + Name: "should-not-be-called", + Do: func(context.Context, reconcile.Params) error { + Fail("should not have been called") + return nil + }, + }, + }, + }) + created := &v1alpha1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: nsn.Name, + Namespace: nsn.Namespace, + }, + } + err := k8sClient.Create(context.Background(), created) + Expect(err).ToNot(HaveOccurred()) + + // test + req := k8sreconcile.Request{ + NamespacedName: nsn, + } + _, err = reconciler.Reconcile(req) + + // verify + Expect(err).To(MatchError(expectedErr)) + Expect(taskCalled).To(BeTrue()) + + // cleanup + Expect(k8sClient.Delete(context.Background(), created)).ToNot(HaveOccurred()) + }) + + It("should skip when the instance doesn't exist", func() { + // prepare + nsn := types.NamespacedName{Name: "non-existing-my-instance", Namespace: "default"} + reconciler := controllers.NewReconciler(controllers.Params{ + Client: k8sClient, + Log: logger, + Scheme: scheme.Scheme, + Config: cfg, + Tasks: []controllers.Task{ + { + Name: "should-not-be-called", + Do: func(context.Context, reconcile.Params) error { + Fail("should not have been called") + return nil + }, + }, + }, + }) + + // test + req := k8sreconcile.Request{ + NamespacedName: nsn, + } + _, err := reconciler.Reconcile(req) + + // verify + Expect(err).ToNot(HaveOccurred()) + }) + + It("should be able to register with the manager", func() { + Skip("this test requires a real cluster, otherwise the GetConfigOrDie will die") + // prepare + mgr, err := manager.New(k8sconfig.GetConfigOrDie(), manager.Options{}) + reconciler := controllers.NewReconciler(controllers.Params{}) + + // test + err = reconciler.SetupWithManager(mgr) + + // verify + Expect(err).ToNot(HaveOccurred()) + }) +}) diff --git a/controllers/suite_test.go b/controllers/suite_test.go new file mode 100644 index 0000000000..27275a0226 --- /dev/null +++ b/controllers/suite_test.go @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// +// 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_test + +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" + + "github.com/open-telemetry/opentelemetry-operator/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 = v1alpha1.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/deploy/crds/simplest.yaml b/deploy/crds/simplest.yaml deleted file mode 100644 index fe2297d839..0000000000 --- a/deploy/crds/simplest.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: opentelemetry.io/v1alpha1 -kind: OpenTelemetryCollector -metadata: - name: simplest -spec: - config: | - receivers: - jaeger: - - processors: - queued-retry: - - exporters: - logging: - - pipelines: - traces: - receivers: [jaeger] - processors: [queued-retry] - exporters: [logging] diff --git a/deploy/olm-catalog/opentelemetry-operator/0.0.1/opentelemetry-operator.v0.0.1.clusterserviceversion.yaml b/deploy/olm-catalog/opentelemetry-operator/0.0.1/opentelemetry-operator.v0.0.1.clusterserviceversion.yaml deleted file mode 100644 index 9fdd592e2c..0000000000 --- a/deploy/olm-catalog/opentelemetry-operator/0.0.1/opentelemetry-operator.v0.0.1.clusterserviceversion.yaml +++ /dev/null @@ -1,127 +0,0 @@ -apiVersion: operators.coreos.com/v1alpha1 -kind: ClusterServiceVersion -metadata: - annotations: - alm-examples: '[{"apiVersion":"opentelemetry.io/v1alpha1","kind":"OpenTelemetryCollector","metadata":{"name":"example-opentelemetrycollector"},"spec":{"size":3}}]' - capabilities: Basic Install - name: opentelemetry-operator.v0.0.1 - namespace: placeholder -spec: - apiservicedefinitions: {} - customresourcedefinitions: {} - description: Placeholder description - displayName: Opentelemetry Operator - install: - spec: - deployments: - - name: opentelemetry-operator - spec: - replicas: 1 - selector: - matchLabels: - name: opentelemetry-operator - strategy: {} - template: - metadata: - labels: - name: opentelemetry-operator - spec: - containers: - - command: - - opentelemetry-operator - env: - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.annotations['olm.targetNamespaces'] - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: OPERATOR_NAME - value: opentelemetry-operator - image: REPLACE_IMAGE - imagePullPolicy: Always - name: opentelemetry-operator - resources: {} - serviceAccountName: opentelemetry-operator - permissions: - - rules: - - apiGroups: - - "" - resources: - - pods - - services - - services/finalizers - - endpoints - - persistentvolumeclaims - - events - - configmaps - - secrets - verbs: - - '*' - - apiGroups: - - apps - resources: - - deployments - - daemonsets - - replicasets - - statefulsets - verbs: - - '*' - - apiGroups: - - monitoring.coreos.com - resources: - - servicemonitors - verbs: - - get - - create - - apiGroups: - - apps - resourceNames: - - opentelemetry-operator - resources: - - deployments/finalizers - verbs: - - update - - apiGroups: - - "" - resources: - - pods - verbs: - - get - - apiGroups: - - apps - resources: - - replicasets - verbs: - - get - - apiGroups: - - opentelemetry.io - resources: - - '*' - verbs: - - '*' - serviceAccountName: opentelemetry-operator - strategy: deployment - installModes: - - supported: true - type: OwnNamespace - - supported: true - type: SingleNamespace - - supported: false - type: MultiNamespace - - supported: true - type: AllNamespaces - keywords: - - tracing - - distributed tracing - - monitoring - - troubleshooting - maintainers: - - email: juraci.github@kroehling.de - name: Juraci Paixão Kröhling - maturity: alpha - provider: - name: OpenTelemetry - version: 0.0.1 diff --git a/deploy/olm-catalog/opentelemetry-operator/0.0.1/opentelemetry_v1alpha1_opentelemetryservice_crd.yaml b/deploy/olm-catalog/opentelemetry-operator/0.0.1/opentelemetry_v1alpha1_opentelemetryservice_crd.yaml deleted file mode 100644 index c04013f59e..0000000000 --- a/deploy/olm-catalog/opentelemetry-operator/0.0.1/opentelemetry_v1alpha1_opentelemetryservice_crd.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: opentelemetrycollectors.opentelemetry.io -spec: - group: opentelemetry.io - names: - kind: OpenTelemetryCollector - listKind: OpenTelemetryCollectorList - plural: opentelemetrycollectors - singular: opentelemetrycollector - scope: Namespaced - subresources: - status: {} - validation: - openAPIV3Schema: - 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/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/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - type: object - status: - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true diff --git a/deploy/olm-catalog/opentelemetry-operator/0.0.2/opentelemetry-operator.v0.0.2.clusterserviceversion.yaml b/deploy/olm-catalog/opentelemetry-operator/0.0.2/opentelemetry-operator.v0.0.2.clusterserviceversion.yaml deleted file mode 100644 index af68abca9f..0000000000 --- a/deploy/olm-catalog/opentelemetry-operator/0.0.2/opentelemetry-operator.v0.0.2.clusterserviceversion.yaml +++ /dev/null @@ -1,168 +0,0 @@ -apiVersion: operators.coreos.com/v1alpha1 -kind: ClusterServiceVersion -metadata: - annotations: - alm-examples: |- - [ - { - "apiVersion": "opentelemetry.io/v1alpha1", - "kind": "OpenTelemetryCollector", - "metadata": { - "name": "simplest" - }, - "spec": { - "config": "receivers:\n jaeger:\n\nprocessors:\n queued-retry:\n\nexporters:\n logging:\n\npipelines:\n traces:\n receivers: [jaeger]\n processors: [queued-retry]\n exporters: [logging]\n" - } - } - ] - capabilities: Basic Install - name: opentelemetry-operator.v0.0.2 - namespace: placeholder -spec: - apiservicedefinitions: {} - customresourcedefinitions: - owned: - - description: OpenTelemetryCollector is the Schema for the opentelemetrycollectors - API - displayName: OpenTelemetry Collector - kind: OpenTelemetryCollector - name: opentelemetrycollectors.opentelemetry.io - specDescriptors: - - description: Args is the set of arguments to pass to the OpenTelemetry Collector - binary - displayName: Args - path: args - - description: Config is the raw JSON to be used as the collector's configuration. - Refer to the OpenTelemetry Collector documentation for details. - displayName: Config - path: config - - description: Image indicates the container image to use for the OpenTelemetry - Collector. - displayName: Image - path: image - - description: Mode represents how the collector should be deployed (deployment - vs. daemonset) - displayName: Mode - path: mode - - description: Replicas is the number of pod instances for the underlying OpenTelemetry - Collector - displayName: Replicas - path: replicas - version: v1alpha1 - description: Placeholder description - displayName: Opentelemetry Operator - install: - spec: - deployments: - - name: opentelemetry-operator - spec: - replicas: 1 - selector: - matchLabels: - name: opentelemetry-operator - strategy: {} - template: - metadata: - labels: - name: opentelemetry-operator - spec: - containers: - - command: - - opentelemetry-operator - env: - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.annotations['olm.targetNamespaces'] - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: OPERATOR_NAME - value: opentelemetry-operator - image: quay.io/opentelemetry/opentelemetry-operator:v0.0.2 - imagePullPolicy: Always - name: opentelemetry-operator - resources: {} - serviceAccountName: opentelemetry-operator - permissions: - - rules: - - apiGroups: - - "" - resources: - - pods - - services - - services/finalizers - - endpoints - - persistentvolumeclaims - - events - - configmaps - - secrets - verbs: - - '*' - - apiGroups: - - apps - resources: - - deployments - - daemonsets - - replicasets - - statefulsets - verbs: - - '*' - - apiGroups: - - monitoring.coreos.com - resources: - - servicemonitors - verbs: - - get - - create - - apiGroups: - - apps - resourceNames: - - opentelemetry-operator - resources: - - deployments/finalizers - verbs: - - update - - apiGroups: - - "" - resources: - - pods - verbs: - - get - - apiGroups: - - apps - resources: - - replicasets - verbs: - - get - - apiGroups: - - opentelemetry.io - resources: - - '*' - verbs: - - '*' - serviceAccountName: opentelemetry-operator - strategy: deployment - installModes: - - supported: true - type: OwnNamespace - - supported: true - type: SingleNamespace - - supported: false - type: MultiNamespace - - supported: true - type: AllNamespaces - keywords: - - tracing - - distributed tracing - - monitoring - - troubleshooting - maintainers: - - email: juraci.github@kroehling.de - name: Juraci Paixão Kröhling - maturity: alpha - provider: - name: OpenTelemetry - replaces: opentelemetry-operator.v0.0.1 - version: 0.0.2 diff --git a/deploy/olm-catalog/opentelemetry-operator/0.0.2/opentelemetry.io_opentelemetrycollectors_crd.yaml b/deploy/olm-catalog/opentelemetry-operator/0.0.2/opentelemetry.io_opentelemetrycollectors_crd.yaml deleted file mode 100644 index c62d155ff5..0000000000 --- a/deploy/olm-catalog/opentelemetry-operator/0.0.2/opentelemetry.io_opentelemetrycollectors_crd.yaml +++ /dev/null @@ -1,86 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: opentelemetrycollectors.opentelemetry.io -spec: - group: opentelemetry.io - names: - kind: OpenTelemetryCollector - listKind: OpenTelemetryCollectorList - plural: opentelemetrycollectors - shortNames: - - otelcol - - otelcols - singular: opentelemetrycollector - scope: Namespaced - subresources: - scale: - specReplicasPath: .spec.replicas - statusReplicasPath: .status.replicas - status: {} - validation: - openAPIV3Schema: - description: OpenTelemetryCollector is the Schema for the opentelemetrycollectors - 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: OpenTelemetryCollectorSpec defines the desired state of OpenTelemetryCollector - properties: - args: - additionalProperties: - type: string - description: Args is the set of arguments to pass to the OpenTelemetry - Collector binary - type: object - config: - description: Config is the raw JSON to be used as the collector's configuration. - Refer to the OpenTelemetry Collector documentation for details. - type: string - image: - description: Image indicates the container image to use for the OpenTelemetry - Collector. - type: string - mode: - description: Mode represents how the collector should be deployed (deployment - vs. daemonset) - enum: - - daemonset - - deployment - type: string - replicas: - description: Replicas is the number of pod instances for the underlying - OpenTelemetry Collector - format: int32 - type: integer - type: object - status: - description: OpenTelemetryCollectorStatus defines the observed state of - OpenTelemetryCollector - properties: - replicas: - format: int32 - type: integer - version: - type: string - required: - - replicas - - version - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true diff --git a/deploy/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry.io_opentelemetrycollectors_crd.yaml b/deploy/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry.io_opentelemetrycollectors_crd.yaml deleted file mode 100644 index db5129cfe8..0000000000 --- a/deploy/olm-catalog/opentelemetry-operator/0.2.0/opentelemetry.io_opentelemetrycollectors_crd.yaml +++ /dev/null @@ -1,1400 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: opentelemetrycollectors.opentelemetry.io -spec: - group: opentelemetry.io - names: - kind: OpenTelemetryCollector - listKind: OpenTelemetryCollectorList - plural: opentelemetrycollectors - shortNames: - - otelcol - - otelcols - singular: opentelemetrycollector - scope: Namespaced - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: OpenTelemetryCollector is the Schema for the opentelemetrycollectors - 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: OpenTelemetryCollectorSpec defines the desired state of OpenTelemetryCollector - properties: - args: - additionalProperties: - type: string - description: Args is the set of arguments to pass to the OpenTelemetry - Collector binary - type: object - config: - description: Config is the raw JSON to be used as the collector's - configuration. Refer to the OpenTelemetry Collector documentation - for details. - type: string - image: - description: Image indicates the container image to use for the OpenTelemetry - Collector. - type: string - mode: - description: Mode represents how the collector should be deployed - (deployment vs. daemonset) - enum: - - daemonset - - deployment - type: string - ports: - description: Ports allows a set of ports to be exposed by the underlying - v1.Service. By default, the operator will attempt to infer the required - ports by parsing the .Spec.Config property but this property can - be used to open aditional ports that can't be inferred by the operator, - like for custom receivers. - items: - description: ServicePort contains information on service's port. - properties: - appProtocol: - description: The application protocol for this port. This field - follows standard Kubernetes label syntax. Un-prefixed names - are reserved for IANA standard service names (as per RFC-6335 - and http://www.iana.org/assignments/service-names). Non-standard - protocols should use prefixed names such as mycompany.com/my-custom-protocol. - Field can be enabled with ServiceAppProtocol feature gate. - type: string - name: - description: The name of this port within the service. This - must be a DNS_LABEL. All ports within a ServiceSpec must have - unique names. When considering the endpoints for a Service, - this must match the 'name' field in the EndpointPort. Optional - if only one ServicePort is defined on this service. - type: string - nodePort: - description: 'The port on each node on which this service is - exposed when type=NodePort or LoadBalancer. Usually assigned - by the system. If specified, it will be allocated to the service - if unused or else creation of the service will fail. Default - is to auto-allocate a port if the ServiceType of this Service - requires one. More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport' - format: int32 - type: integer - port: - description: The port that will be exposed by this service. - format: int32 - type: integer - protocol: - description: The IP protocol for this port. Supports "TCP", - "UDP", and "SCTP". Default is TCP. - type: string - targetPort: - anyOf: - - type: integer - - type: string - description: 'Number or name of the port to access on the pods - targeted by the service. Number must be in the range 1 to - 65535. Name must be an IANA_SVC_NAME. If this is a string, - it will be looked up as a named port in the target Pod''s - container ports. If this is not specified, the value of the - ''port'' field is used (an identity map). This field is ignored - for services with clusterIP=None, and should be omitted or - set equal to the ''port'' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service' - x-kubernetes-int-or-string: true - required: - - port - type: object - type: array - x-kubernetes-list-type: atomic - replicas: - description: Replicas is the number of pod instances for the underlying - OpenTelemetry Collector - format: int32 - type: integer - serviceAccount: - description: ServiceAccount indicates the name of an existing service - account to use with this instance. - type: string - volumeMounts: - description: VolumeMounts represents the mount points to use in the - underlying collector deployment(s) - items: - description: VolumeMount describes a mounting of a Volume within - a container. - properties: - mountPath: - description: Path within the container at which the volume should - be mounted. Must not contain ':'. - type: string - mountPropagation: - description: mountPropagation determines how mounts are propagated - from the host to container and the other way around. When - not set, MountPropagationNone is used. This field is beta - in 1.10. - type: string - name: - description: This must match the Name of a Volume. - type: string - readOnly: - description: Mounted read-only if true, read-write otherwise - (false or unspecified). Defaults to false. - type: boolean - subPath: - description: Path within the volume from which the container's - volume should be mounted. Defaults to "" (volume's root). - type: string - subPathExpr: - description: Expanded path within the volume from which the - container's volume should be mounted. Behaves similarly to - SubPath but environment variable references $(VAR_NAME) are - expanded using the container's environment. Defaults to "" - (volume's root). SubPathExpr and SubPath are mutually exclusive. - type: string - required: - - mountPath - - name - type: object - type: array - x-kubernetes-list-type: atomic - volumes: - description: Volumes represents which volumes to use in the underlying - collector deployment(s). - items: - description: Volume represents a named volume in a pod that may - be accessed by any container in the pod. - properties: - awsElasticBlockStore: - description: 'AWSElasticBlockStore represents an AWS Disk resource - that is attached to a kubelet''s host machine and then exposed - to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' - properties: - fsType: - description: 'Filesystem type of the volume that you want - to mount. Tip: Ensure that the filesystem type is supported - by the host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from - compromising the machine' - type: string - partition: - description: 'The partition in the volume that you want - to mount. If omitted, the default is to mount by volume - name. Examples: For volume /dev/sda1, you specify the - partition as "1". Similarly, the volume partition for - /dev/sda is "0" (or you can leave the property empty).' - format: int32 - type: integer - readOnly: - description: 'Specify "true" to force and set the ReadOnly - property in VolumeMounts to "true". If omitted, the default - is "false". More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' - type: boolean - volumeID: - description: 'Unique ID of the persistent disk resource - in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' - type: string - required: - - volumeID - type: object - azureDisk: - description: AzureDisk represents an Azure Data Disk mount on - the host and bind mount to the pod. - properties: - cachingMode: - description: 'Host Caching mode: None, Read Only, Read Write.' - type: string - diskName: - description: The Name of the data disk in the blob storage - type: string - diskURI: - description: The URI the data disk in the blob storage - type: string - fsType: - description: Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Ex. "ext4", - "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - kind: - description: 'Expected values Shared: multiple blob disks - per storage account Dedicated: single blob disk per storage - account Managed: azure managed data disk (only in managed - availability set). defaults to shared' - type: string - readOnly: - description: Defaults to false (read/write). ReadOnly here - will force the ReadOnly setting in VolumeMounts. - type: boolean - required: - - diskName - - diskURI - type: object - azureFile: - description: AzureFile represents an Azure File Service mount - on the host and bind mount to the pod. - properties: - readOnly: - description: Defaults to false (read/write). ReadOnly here - will force the ReadOnly setting in VolumeMounts. - type: boolean - secretName: - description: the name of secret that contains Azure Storage - Account Name and Key - type: string - shareName: - description: Share Name - type: string - required: - - secretName - - shareName - type: object - cephfs: - description: CephFS represents a Ceph FS mount on the host that - shares a pod's lifetime - properties: - monitors: - description: 'Required: Monitors is a collection of Ceph - monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - items: - type: string - type: array - path: - description: 'Optional: Used as the mounted root, rather - than the full Ceph tree, default is /' - type: string - readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - type: boolean - secretFile: - description: 'Optional: SecretFile is the path to key ring - for User, default is /etc/ceph/user.secret More info: - https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - type: string - secretRef: - description: 'Optional: SecretRef is reference to the authentication - secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - user: - description: 'Optional: User is the rados user name, default - is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' - type: string - required: - - monitors - type: object - cinder: - description: 'Cinder represents a cinder volume attached and - mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - properties: - fsType: - description: 'Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Examples: - "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" - if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - type: string - readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting in VolumeMounts. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - type: boolean - secretRef: - description: 'Optional: points to a secret object containing - parameters used to connect to OpenStack.' - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - volumeID: - description: 'volume id used to identify the volume in cinder. - More info: https://examples.k8s.io/mysql-cinder-pd/README.md' - type: string - required: - - volumeID - type: object - configMap: - description: ConfigMap represents a configMap that should populate - this volume - properties: - defaultMode: - description: 'Optional: mode bits to use on created files - by default. Must be a value between 0 and 0777. Defaults - to 0644. Directories within the path are not affected - by this setting. This might be in conflict with other - options that affect the file mode, like fsGroup, and the - result can be other mode bits set.' - format: int32 - type: integer - items: - description: If unspecified, each key-value pair in the - Data field of the referenced ConfigMap will be projected - into the volume as a file whose name is the key and content - is the value. If specified, the listed keys will be projected - into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in - the ConfigMap, the volume setup will error unless it is - marked optional. Paths must be relative and may not contain - the '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits to use on this file, - must be a value between 0 and 0777. If not specified, - the volume defaultMode will be used. This might - be in conflict with other options that affect the - file mode, like fsGroup, and the result can be other - mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file to map - the key to. May not be an absolute path. May not - contain the path element '..'. May not start with - the string '..'. - type: string - required: - - key - - path - type: object - type: array - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - optional: - description: Specify whether the ConfigMap or its keys must - be defined - type: boolean - type: object - csi: - description: CSI (Container Storage Interface) represents storage - that is handled by an external CSI driver (Alpha feature). - properties: - driver: - description: Driver is the name of the CSI driver that handles - this volume. Consult with your admin for the correct name - as registered in the cluster. - type: string - fsType: - description: Filesystem type to mount. Ex. "ext4", "xfs", - "ntfs". If not provided, the empty value is passed to - the associated CSI driver which will determine the default - filesystem to apply. - type: string - nodePublishSecretRef: - description: NodePublishSecretRef is a reference to the - secret object containing sensitive information to pass - to the CSI driver to complete the CSI NodePublishVolume - and NodeUnpublishVolume calls. This field is optional, - and may be empty if no secret is required. If the secret - object contains more than one secret, all secret references - are passed. - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - readOnly: - description: Specifies a read-only configuration for the - volume. Defaults to false (read/write). - type: boolean - volumeAttributes: - additionalProperties: - type: string - description: VolumeAttributes stores driver-specific properties - that are passed to the CSI driver. Consult your driver's - documentation for supported values. - type: object - required: - - driver - type: object - downwardAPI: - description: DownwardAPI represents downward API about the pod - that should populate this volume - properties: - defaultMode: - description: 'Optional: mode bits to use on created files - by default. Must be a value between 0 and 0777. Defaults - to 0644. Directories within the path are not affected - by this setting. This might be in conflict with other - options that affect the file mode, like fsGroup, and the - result can be other mode bits set.' - format: int32 - type: integer - items: - description: Items is a list of downward API volume file - items: - description: DownwardAPIVolumeFile represents information - to create the file containing the pod field - properties: - fieldRef: - description: 'Required: Selects a field of the pod: - only annotations, labels, name and namespace are - supported.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". - type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - mode: - description: 'Optional: mode bits to use on this file, - must be a value between 0 and 0777. If not specified, - the volume defaultMode will be used. This might - be in conflict with other options that affect the - file mode, like fsGroup, and the result can be other - mode bits set.' - format: int32 - type: integer - path: - description: 'Required: Path is the relative path - name of the file to be created. Must not be absolute - or contain the ''..'' path. Must be utf-8 encoded. - The first item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: 'Selects a resource of the container: - only resources limits and requests (limits.cpu, - limits.memory, requests.cpu and requests.memory) - are currently supported.' - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' - type: string - required: - - resource - type: object - required: - - path - type: object - type: array - type: object - emptyDir: - description: 'EmptyDir represents a temporary directory that - shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' - properties: - medium: - description: 'What type of storage medium should back this - directory. The default is "" which means to use the node''s - default medium. Must be an empty string (default) or Memory. - More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' - type: string - sizeLimit: - anyOf: - - type: integer - - type: string - description: 'Total amount of local storage required for - this EmptyDir volume. The size limit is also applicable - for memory medium. The maximum usage on memory medium - EmptyDir would be the minimum value between the SizeLimit - specified here and the sum of memory limits of all containers - in a pod. The default is nil which means that the limit - is undefined. More info: http://kubernetes.io/docs/user-guide/volumes#emptydir' - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - type: object - fc: - description: FC represents a Fibre Channel resource that is - attached to a kubelet's host machine and then exposed to the - pod. - properties: - fsType: - description: 'Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Ex. "ext4", - "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from - compromising the machine' - type: string - lun: - description: 'Optional: FC target lun number' - format: int32 - type: integer - readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting in VolumeMounts.' - type: boolean - targetWWNs: - description: 'Optional: FC target worldwide names (WWNs)' - items: - type: string - type: array - wwids: - description: 'Optional: FC volume world wide identifiers - (wwids) Either wwids or combination of targetWWNs and - lun must be set, but not both simultaneously.' - items: - type: string - type: array - type: object - flexVolume: - description: FlexVolume represents a generic volume resource - that is provisioned/attached using an exec based plugin. - properties: - driver: - description: Driver is the name of the driver to use for - this volume. - type: string - fsType: - description: Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Ex. "ext4", - "xfs", "ntfs". The default filesystem depends on FlexVolume - script. - type: string - options: - additionalProperties: - type: string - description: 'Optional: Extra command options if any.' - type: object - readOnly: - description: 'Optional: Defaults to false (read/write). - ReadOnly here will force the ReadOnly setting in VolumeMounts.' - type: boolean - secretRef: - description: 'Optional: SecretRef is reference to the secret - object containing sensitive information to pass to the - plugin scripts. This may be empty if no secret object - is specified. If the secret object contains more than - one secret, all secrets are passed to the plugin scripts.' - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - required: - - driver - type: object - flocker: - description: Flocker represents a Flocker volume attached to - a kubelet's host machine. This depends on the Flocker control - service being running - properties: - datasetName: - description: Name of the dataset stored as metadata -> name - on the dataset for Flocker should be considered as deprecated - type: string - datasetUUID: - description: UUID of the dataset. This is unique identifier - of a Flocker dataset - type: string - type: object - gcePersistentDisk: - description: 'GCEPersistentDisk represents a GCE Disk resource - that is attached to a kubelet''s host machine and then exposed - to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - properties: - fsType: - description: 'Filesystem type of the volume that you want - to mount. Tip: Ensure that the filesystem type is supported - by the host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from - compromising the machine' - type: string - partition: - description: 'The partition in the volume that you want - to mount. If omitted, the default is to mount by volume - name. Examples: For volume /dev/sda1, you specify the - partition as "1". Similarly, the volume partition for - /dev/sda is "0" (or you can leave the property empty). - More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - format: int32 - type: integer - pdName: - description: 'Unique name of the PD resource in GCE. Used - to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - type: string - readOnly: - description: 'ReadOnly here will force the ReadOnly setting - in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' - type: boolean - required: - - pdName - type: object - gitRepo: - description: 'GitRepo represents a git repository at a particular - revision. DEPRECATED: GitRepo is deprecated. To provision - a container with a git repo, mount an EmptyDir into an InitContainer - that clones the repo using git, then mount the EmptyDir into - the Pod''s container.' - properties: - directory: - description: Target directory name. Must not contain or - start with '..'. If '.' is supplied, the volume directory - will be the git repository. Otherwise, if specified, - the volume will contain the git repository in the subdirectory - with the given name. - type: string - repository: - description: Repository URL - type: string - revision: - description: Commit hash for the specified revision. - type: string - required: - - repository - type: object - glusterfs: - description: 'Glusterfs represents a Glusterfs mount on the - host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' - properties: - endpoints: - description: 'EndpointsName is the endpoint name that details - Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' - type: string - path: - description: 'Path is the Glusterfs volume path. More info: - https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' - type: string - readOnly: - description: 'ReadOnly here will force the Glusterfs volume - to be mounted with read-only permissions. Defaults to - false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' - type: boolean - required: - - endpoints - - path - type: object - hostPath: - description: 'HostPath represents a pre-existing file or directory - on the host machine that is directly exposed to the container. - This is generally used for system agents or other privileged - things that are allowed to see the host machine. Most containers - will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- TODO(jonesdl) We need to restrict who can use host directory - mounts and who can/can not mount host directories as read/write.' - properties: - path: - description: 'Path of the directory on the host. If the - path is a symlink, it will follow the link to the real - path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' - type: string - type: - description: 'Type for HostPath Volume Defaults to "" More - info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' - type: string - required: - - path - type: object - iscsi: - description: 'ISCSI represents an ISCSI Disk resource that is - attached to a kubelet''s host machine and then exposed to - the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' - properties: - chapAuthDiscovery: - description: whether support iSCSI Discovery CHAP authentication - type: boolean - chapAuthSession: - description: whether support iSCSI Session CHAP authentication - type: boolean - fsType: - description: 'Filesystem type of the volume that you want - to mount. Tip: Ensure that the filesystem type is supported - by the host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from - compromising the machine' - type: string - initiatorName: - description: Custom iSCSI Initiator Name. If initiatorName - is specified with iscsiInterface simultaneously, new iSCSI - interface : will be created - for the connection. - type: string - iqn: - description: Target iSCSI Qualified Name. - type: string - iscsiInterface: - description: iSCSI Interface Name that uses an iSCSI transport. - Defaults to 'default' (tcp). - type: string - lun: - description: iSCSI Target Lun number. - format: int32 - type: integer - portals: - description: iSCSI Target Portal List. The portal is either - an IP or ip_addr:port if the port is other than default - (typically TCP ports 860 and 3260). - items: - type: string - type: array - readOnly: - description: ReadOnly here will force the ReadOnly setting - in VolumeMounts. Defaults to false. - type: boolean - secretRef: - description: CHAP Secret for iSCSI target and initiator - authentication - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - targetPortal: - description: iSCSI Target Portal. The Portal is either an - IP or ip_addr:port if the port is other than default (typically - TCP ports 860 and 3260). - type: string - required: - - iqn - - lun - - targetPortal - type: object - name: - description: 'Volume''s name. Must be a DNS_LABEL and unique - within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - nfs: - description: 'NFS represents an NFS mount on the host that shares - a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - properties: - path: - description: 'Path that is exported by the NFS server. More - info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - type: string - readOnly: - description: 'ReadOnly here will force the NFS export to - be mounted with read-only permissions. Defaults to false. - More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - type: boolean - server: - description: 'Server is the hostname or IP address of the - NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' - type: string - required: - - path - - server - type: object - persistentVolumeClaim: - description: 'PersistentVolumeClaimVolumeSource represents a - reference to a PersistentVolumeClaim in the same namespace. - More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' - properties: - claimName: - description: 'ClaimName is the name of a PersistentVolumeClaim - in the same namespace as the pod using this volume. More - info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' - type: string - readOnly: - description: Will force the ReadOnly setting in VolumeMounts. - Default false. - type: boolean - required: - - claimName - type: object - photonPersistentDisk: - description: PhotonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host machine - properties: - fsType: - description: Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Ex. "ext4", - "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - pdID: - description: ID that identifies Photon Controller persistent - disk - type: string - required: - - pdID - type: object - portworxVolume: - description: PortworxVolume represents a portworx volume attached - and mounted on kubelets host machine - properties: - fsType: - description: FSType represents the filesystem type to mount - Must be a filesystem type supported by the host operating - system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" - if unspecified. - type: string - readOnly: - description: Defaults to false (read/write). ReadOnly here - will force the ReadOnly setting in VolumeMounts. - type: boolean - volumeID: - description: VolumeID uniquely identifies a Portworx volume - type: string - required: - - volumeID - type: object - projected: - description: Items for all in one resources secrets, configmaps, - and downward API - properties: - defaultMode: - description: Mode bits to use on created files by default. - Must be a value between 0 and 0777. Directories within - the path are not affected by this setting. This might - be in conflict with other options that affect the file - mode, like fsGroup, and the result can be other mode bits - set. - format: int32 - type: integer - sources: - description: list of volume projections - items: - description: Projection that may be projected along with - other supported volume types - properties: - configMap: - description: information about the configMap data - to project - properties: - items: - description: If unspecified, each key-value pair - in the Data field of the referenced ConfigMap - will be projected into the volume as a file - whose name is the key and content is the value. - If specified, the listed keys will be projected - into the specified paths, and unlisted keys - will not be present. If a key is specified which - is not present in the ConfigMap, the volume - setup will error unless it is marked optional. - Paths must be relative and may not contain the - '..' path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits to use - on this file, must be a value between - 0 and 0777. If not specified, the volume - defaultMode will be used. This might be - in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file - to map the key to. May not be an absolute - path. May not contain the path element - '..'. May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' - type: string - optional: - description: Specify whether the ConfigMap or - its keys must be defined - type: boolean - type: object - downwardAPI: - description: information about the downwardAPI data - to project - properties: - items: - description: Items is a list of DownwardAPIVolume - file - items: - description: DownwardAPIVolumeFile represents - information to create the file containing - the pod field - properties: - fieldRef: - description: 'Required: Selects a field - of the pod: only annotations, labels, - name and namespace are supported.' - properties: - apiVersion: - description: Version of the schema the - FieldPath is written in terms of, - defaults to "v1". - type: string - fieldPath: - description: Path of the field to select - in the specified API version. - type: string - required: - - fieldPath - type: object - mode: - description: 'Optional: mode bits to use - on this file, must be a value between - 0 and 0777. If not specified, the volume - defaultMode will be used. This might be - in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - path: - description: 'Required: Path is the relative - path name of the file to be created. Must - not be absolute or contain the ''..'' - path. Must be utf-8 encoded. The first - item of the relative path must not start - with ''..''' - type: string - resourceFieldRef: - description: 'Selects a resource of the - container: only resources limits and requests - (limits.cpu, limits.memory, requests.cpu - and requests.memory) are currently supported.' - properties: - containerName: - description: 'Container name: required - for volumes, optional for env vars' - type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format - of the exposed resources, defaults - to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to - select' - type: string - required: - - resource - type: object - required: - - path - type: object - type: array - type: object - secret: - description: information about the secret data to - project - properties: - items: - description: If unspecified, each key-value pair - in the Data field of the referenced Secret will - be projected into the volume as a file whose - name is the key and content is the value. If - specified, the listed keys will be projected - into the specified paths, and unlisted keys - will not be present. If a key is specified which - is not present in the Secret, the volume setup - will error unless it is marked optional. Paths - must be relative and may not contain the '..' - path or start with '..'. - items: - description: Maps a string key to a path within - a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits to use - on this file, must be a value between - 0 and 0777. If not specified, the volume - defaultMode will be used. This might be - in conflict with other options that affect - the file mode, like fsGroup, and the result - can be other mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file - to map the key to. May not be an absolute - path. May not contain the path element - '..'. May not start with the string '..'. - type: string - required: - - key - - path - type: object - type: array - name: - description: 'Name of the referent. More info: - https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' - type: string - optional: - description: Specify whether the Secret or its - key must be defined - type: boolean - type: object - serviceAccountToken: - description: information about the serviceAccountToken - data to project - properties: - audience: - description: Audience is the intended audience - of the token. A recipient of a token must identify - itself with an identifier specified in the audience - of the token, and otherwise should reject the - token. The audience defaults to the identifier - of the apiserver. - type: string - expirationSeconds: - description: ExpirationSeconds is the requested - duration of validity of the service account - token. As the token approaches expiration, the - kubelet volume plugin will proactively rotate - the service account token. The kubelet will - start trying to rotate the token if the token - is older than 80 percent of its time to live - or if the token is older than 24 hours.Defaults - to 1 hour and must be at least 10 minutes. - format: int64 - type: integer - path: - description: Path is the path relative to the - mount point of the file to project the token - into. - type: string - required: - - path - type: object - type: object - type: array - required: - - sources - type: object - quobyte: - description: Quobyte represents a Quobyte mount on the host - that shares a pod's lifetime - properties: - group: - description: Group to map volume access to Default is no - group - type: string - readOnly: - description: ReadOnly here will force the Quobyte volume - to be mounted with read-only permissions. Defaults to - false. - type: boolean - registry: - description: Registry represents a single or multiple Quobyte - Registry services specified as a string as host:port pair - (multiple entries are separated with commas) which acts - as the central registry for volumes - type: string - tenant: - description: Tenant owning the given Quobyte volume in the - Backend Used with dynamically provisioned Quobyte volumes, - value is set by the plugin - type: string - user: - description: User to map volume access to Defaults to serivceaccount - user - type: string - volume: - description: Volume is a string that references an already - created Quobyte volume by name. - type: string - required: - - registry - - volume - type: object - rbd: - description: 'RBD represents a Rados Block Device mount on the - host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' - properties: - fsType: - description: 'Filesystem type of the volume that you want - to mount. Tip: Ensure that the filesystem type is supported - by the host operating system. Examples: "ext4", "xfs", - "ntfs". Implicitly inferred to be "ext4" if unspecified. - More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from - compromising the machine' - type: string - image: - description: 'The rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - keyring: - description: 'Keyring is the path to key ring for RBDUser. - Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - monitors: - description: 'A collection of Ceph monitors. More info: - https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - items: - type: string - type: array - pool: - description: 'The rados pool name. Default is rbd. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - readOnly: - description: 'ReadOnly here will force the ReadOnly setting - in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: boolean - secretRef: - description: 'SecretRef is name of the authentication secret - for RBDUser. If provided overrides keyring. Default is - nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - user: - description: 'The rados user name. Default is admin. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' - type: string - required: - - image - - monitors - type: object - scaleIO: - description: ScaleIO represents a ScaleIO persistent volume - attached and mounted on Kubernetes nodes. - properties: - fsType: - description: Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Ex. "ext4", - "xfs", "ntfs". Default is "xfs". - type: string - gateway: - description: The host address of the ScaleIO API Gateway. - type: string - protectionDomain: - description: The name of the ScaleIO Protection Domain for - the configured storage. - type: string - readOnly: - description: Defaults to false (read/write). ReadOnly here - will force the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: SecretRef references to the secret for ScaleIO - user and other sensitive information. If this is not provided, - Login operation will fail. - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - sslEnabled: - description: Flag to enable/disable SSL communication with - Gateway, default false - type: boolean - storageMode: - description: Indicates whether the storage for a volume - should be ThickProvisioned or ThinProvisioned. Default - is ThinProvisioned. - type: string - storagePool: - description: The ScaleIO Storage Pool associated with the - protection domain. - type: string - system: - description: The name of the storage system as configured - in ScaleIO. - type: string - volumeName: - description: The name of a volume already created in the - ScaleIO system that is associated with this volume source. - type: string - required: - - gateway - - secretRef - - system - type: object - secret: - description: 'Secret represents a secret that should populate - this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' - properties: - defaultMode: - description: 'Optional: mode bits to use on created files - by default. Must be a value between 0 and 0777. Defaults - to 0644. Directories within the path are not affected - by this setting. This might be in conflict with other - options that affect the file mode, like fsGroup, and the - result can be other mode bits set.' - format: int32 - type: integer - items: - description: If unspecified, each key-value pair in the - Data field of the referenced Secret will be projected - into the volume as a file whose name is the key and content - is the value. If specified, the listed keys will be projected - into the specified paths, and unlisted keys will not be - present. If a key is specified which is not present in - the Secret, the volume setup will error unless it is marked - optional. Paths must be relative and may not contain the - '..' path or start with '..'. - items: - description: Maps a string key to a path within a volume. - properties: - key: - description: The key to project. - type: string - mode: - description: 'Optional: mode bits to use on this file, - must be a value between 0 and 0777. If not specified, - the volume defaultMode will be used. This might - be in conflict with other options that affect the - file mode, like fsGroup, and the result can be other - mode bits set.' - format: int32 - type: integer - path: - description: The relative path of the file to map - the key to. May not be an absolute path. May not - contain the path element '..'. May not start with - the string '..'. - type: string - required: - - key - - path - type: object - type: array - optional: - description: Specify whether the Secret or its keys must - be defined - type: boolean - secretName: - description: 'Name of the secret in the pod''s namespace - to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' - type: string - type: object - storageos: - description: StorageOS represents a StorageOS volume attached - and mounted on Kubernetes nodes. - properties: - fsType: - description: Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Ex. "ext4", - "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - readOnly: - description: Defaults to false (read/write). ReadOnly here - will force the ReadOnly setting in VolumeMounts. - type: boolean - secretRef: - description: SecretRef specifies the secret to use for obtaining - the StorageOS API credentials. If not specified, default - values will be attempted. - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - volumeName: - description: VolumeName is the human-readable name of the - StorageOS volume. Volume names are only unique within - a namespace. - type: string - volumeNamespace: - description: VolumeNamespace specifies the scope of the - volume within StorageOS. If no namespace is specified - then the Pod's namespace will be used. This allows the - Kubernetes name scoping to be mirrored within StorageOS - for tighter integration. Set VolumeName to any name to - override the default behaviour. Set to "default" if you - are not using namespaces within StorageOS. Namespaces - that do not pre-exist within StorageOS will be created. - type: string - type: object - vsphereVolume: - description: VsphereVolume represents a vSphere volume attached - and mounted on kubelets host machine - properties: - fsType: - description: Filesystem type to mount. Must be a filesystem - type supported by the host operating system. Ex. "ext4", - "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - type: string - storagePolicyID: - description: Storage Policy Based Management (SPBM) profile - ID associated with the StoragePolicyName. - type: string - storagePolicyName: - description: Storage Policy Based Management (SPBM) profile - name. - type: string - volumePath: - description: Path that identifies vSphere volume vmdk - type: string - required: - - volumePath - type: object - required: - - name - type: object - type: array - x-kubernetes-list-type: atomic - type: object - status: - description: OpenTelemetryCollectorStatus defines the observed state of - OpenTelemetryCollector - properties: - replicas: - format: int32 - type: integer - version: - type: string - required: - - replicas - - version - type: object - type: object - served: true - storage: true - subresources: - scale: - specReplicasPath: .spec.replicas - statusReplicasPath: .status.replicas - status: {} diff --git a/deploy/olm-catalog/opentelemetry-operator/opentelemetry-operator.package.yaml b/deploy/olm-catalog/opentelemetry-operator/opentelemetry-operator.package.yaml deleted file mode 100644 index 374263beca..0000000000 --- a/deploy/olm-catalog/opentelemetry-operator/opentelemetry-operator.package.yaml +++ /dev/null @@ -1,5 +0,0 @@ -channels: -- currentCSV: opentelemetry-operator.v0.2.0 - name: alpha -defaultChannel: alpha -packageName: opentelemetry-operator diff --git a/deploy/operator.yaml b/deploy/operator.yaml deleted file mode 100644 index b930e37d81..0000000000 --- a/deploy/operator.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: opentelemetry-operator -spec: - replicas: 1 - selector: - matchLabels: - name: opentelemetry-operator - template: - metadata: - labels: - name: opentelemetry-operator - spec: - serviceAccountName: opentelemetry-operator - containers: - - name: opentelemetry-operator - image: quay.io/opentelemetry/opentelemetry-operator:v0.2.0 - command: - - opentelemetry-operator - imagePullPolicy: Always - env: - - name: WATCH_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: OPERATOR_NAME - value: "opentelemetry-operator" diff --git a/deploy/role.yaml b/deploy/role.yaml deleted file mode 100644 index 39b35b1553..0000000000 --- a/deploy/role.yaml +++ /dev/null @@ -1,80 +0,0 @@ -kind: Role -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: opentelemetry-operator -rules: -- apiGroups: - - "" - resources: - - pods - - services - - services/finalizers - - endpoints - - persistentvolumeclaims - - events - - configmaps - - secrets - - serviceaccounts - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - apps - resources: - - deployments - - daemonsets - - replicasets - - statefulsets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - monitoring.coreos.com - resources: - - servicemonitors - verbs: - - get - - create -- apiGroups: - - apps - resourceNames: - - opentelemetry-operator - resources: - - deployments/finalizers - verbs: - - update -- apiGroups: - - "" - resources: - - pods - verbs: - - get -- apiGroups: - - apps - resources: - - replicasets - - deployments - verbs: - - get -- apiGroups: - - opentelemetry.io - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch diff --git a/deploy/service_account.yaml b/deploy/service_account.yaml deleted file mode 100644 index f97a12acbf..0000000000 --- a/deploy/service_account.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: opentelemetry-operator diff --git a/examples/business-application.yaml b/examples/business-application.yaml deleted file mode 100644 index 63551e99da..0000000000 --- a/examples/business-application.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# when `simplest.yaml` is deployed, this is how an application containing the Jaeger client can be configured to use otelcol -# in this case, we make use of the jaeger-agent as a sidecar, and the jaeger-agent connects to otelcol via gRPC -# this is suitable when the application is already configured to talk to Jaeger via UDP -# for greenfield applications, the OpenTelemetry client should be preferred -apiVersion: apps/v1 -kind: Deployment -metadata: - name: myapp -spec: - selector: - matchLabels: - app: myapp - template: - metadata: - labels: - app: myapp - spec: - containers: - - name: myapp - image: jaegertracing/vertx-create-span:operator-e2e-tests - - name: jaeger-agent - image: jaegertracing/jaeger-agent:1.14.0 - args: - - --reporter.grpc.host-port=dns:///simplest-collector-headless.default:14250 - - --reporter.type=grpc - ports: - - containerPort: 5778 - name: config-rest - protocol: TCP - - containerPort: 6831 - name: jg-compact-trft - protocol: TCP diff --git a/examples/daemonset.yaml b/examples/daemonset.yaml deleted file mode 100644 index 8cb9f529ef..0000000000 --- a/examples/daemonset.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: opentelemetry.io/v1alpha1 -kind: OpenTelemetryCollector -metadata: - name: otelcol-as-daemonset -spec: - mode: daemonset - config: | - receivers: - jaeger: - - processors: - queued-retry: - - exporters: - logging: - - pipelines: - traces: - receivers: [jaeger] - processors: [queued-retry] - exporters: [logging] diff --git a/examples/with-volumes.yaml b/examples/with-volumes.yaml deleted file mode 100644 index dfb5a5ff60..0000000000 --- a/examples/with-volumes.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: opentelemetry.io/v1alpha1 -kind: OpenTelemetryCollector -metadata: - name: with-volumes -spec: - config: | - receivers: - jaeger: - - processors: - queued_retry: - - exporters: - logging: - - service: - pipelines: - traces: - receivers: [jaeger] - processors: [queued_retry] - exporters: [logging] - - volumeMounts: - - mountPath: /etc/tls-certs - name: tls-certs-volume - - volumes: - - name: tls-certs-volume - secret: - secretName: tls-certs-secret diff --git a/go.mod b/go.mod index e63b45a986..ea0631abc6 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,14 @@ module github.com/open-telemetry/opentelemetry-operator go 1.13 require ( - github.com/coreos/prometheus-operator v0.38.1-0.20200424145508-7e176fda06cc github.com/go-logr/logr v0.1.0 - github.com/go-openapi/spec v0.19.4 - github.com/magiconair/properties v1.8.0 - github.com/operator-framework/operator-sdk v0.18.1 + github.com/onsi/ginkgo v1.11.0 // keep the Makefile in sync! + github.com/onsi/gomega v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.4.0 - github.com/stretchr/testify v1.5.1 - go.uber.org/zap v1.14.1 gopkg.in/yaml.v2 v2.2.8 - gotest.tools v2.2.0+incompatible - k8s.io/api v0.18.2 - k8s.io/apimachinery v0.18.2 - k8s.io/client-go v12.0.0+incompatible - k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c + k8s.io/api v0.18.6 + k8s.io/apimachinery v0.18.6 + k8s.io/client-go v0.18.6 + k8s.io/kubectl v0.18.6 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 611c84e0e9..00c8c8d3a5 100644 --- a/go.sum +++ b/go.sum @@ -1,1266 +1,348 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= -bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= 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/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -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 v32.5.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 v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v11.2.8+incompatible h1:Q2feRPMlcfVcqz3pF87PJzkm5lZrL+x6BDtzhODzNJM= -github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -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 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= 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 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= 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 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM= 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 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0= 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.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= -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.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= -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.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -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.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -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/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= -github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig/v3 v3.0.0/go.mod h1:NEUY/Qq8Gdm2xgYA+NwJM6wmfdRV9xkh8h/Rld20R0U= -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.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= -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.12/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.0.0-20190417211021-672e52e9209d/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= -github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= -github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= -github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.0.1/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 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg= -github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/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/ant31/crd-validation v0.0.0-20180702145049-30f8a35d0ac2/go.mod h1:X0noFIik9YqfhGYBLEHg8LJKEwy7QIitLQuFMpKLcPk= -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/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7/go.mod h1:LWMyo4iOLWXHGdBki7NIht1kHru/0wM179h+d3g8ATM= -github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -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/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e/go.mod h1:uHBSeeATKpVazAACZBDPL/Nk/UhQDDsJWDlqYJo8/Us= -github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= -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/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= -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/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -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/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= -github.com/brancz/gojsontoyaml v0.0.0-20190425155809-e8bd32d46b3d/go.mod h1:IyUJYN1gvWjtLF5ZuygmxbnsAyP3aJS6cHzIuZY50B0= -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/bugsnag-go v1.5.0/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/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= -github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= -github.com/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/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY= -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 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= -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/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho= -github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/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/cloudflare/cfssl v0.0.0-20180726162950-56268a613adf/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= -github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= -github.com/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/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= -github.com/container-storage-interface/spec v1.1.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= -github.com/containerd/console v0.0.0-20170925154832-84eeaae905fa/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.2.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0-beta.2.0.20190823190603-4a2f61c4f2b4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -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/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= -github.com/coredns/corefile-migration v1.0.2/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E= -github.com/coreos/bbolt v1.3.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.13+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= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/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.34.0 h1:TF9qaydNeUamLKs0hniaapa4FBz8U8TIlRRtJX987A4= -github.com/coreos/prometheus-operator v0.34.0/go.mod h1:Li6rMllG/hYIyXfMuvUwhyC+hqwJVHdsDdP21hypT1M= -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/coreos/prometheus-operator v0.39.0 h1:sXbjqxHhTdfhdbG/Fpls3nArXZZaC66JTpzebZK2ZOc= -github.com/coreos/prometheus-operator v0.39.0/go.mod h1:erio69w1R/aC14D5nfvAXSlE8FT8jt2Hnavc50Dp33A= -github.com/coreos/rkt v1.30.0/go.mod h1:O634mlH6U7qk87poQifK6M2rsFNt+FyUTWNMnP1hF1U= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/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.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM= -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-20190506213505-d88565df0c2d/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -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-0.20190205005809-0d3efadf0154+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.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= -github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= -github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82/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/libnetwork v0.0.0-20180830151422-a9cd636e3789/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8= -github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -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 h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w= -github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.11.1+incompatible h1:CjKsv3uWcCMvySPQYKxO8XX3f9zD4FeZRsW4G0B4ffE= -github.com/emicklei/go-restful v2.11.1+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/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/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= -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.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 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/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -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/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -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/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= -github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= -github.com/go-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 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.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 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.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 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo= -github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= -github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= 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.4 h1:i/65mCM9s1h8eCkT07F5Z/C1e/f8VTgEwer+00yevpA= -github.com/go-openapi/swag v0.19.4/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE= -github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= -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-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= -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.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -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 v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -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/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= -github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/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 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= 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 h1:X+zN6RZXsvnrSJaAIQhZezPfAfvsqihKKR8oiLHid34= -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-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20181024230925-c65c006176ff/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/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 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.0.0/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/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -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/cadvisor v0.34.0/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-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-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= -github.com/google/go-cmp v0.4.1/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 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= 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 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= 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.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.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/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/googleapis/gnostic v0.4.2 h1:uh5EXM/5/ki6d0p/FoUxuiN8KHpo1w572UXQdB2MnTg= -github.com/googleapis/gnostic v0.4.2/go.mod h1:P0d+GwDcJO8XvMi7aihGGl/CkivFa9JX/V/FfjyYzI0= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.2.0 h1:lD2Bce2xBAMNNcFZ0dObTpXkGLlVIb33RPVUNVpw6ic= -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 h1:F7WD09S8QB4LrkEpka0dFPLSotH11HRpCsLIbIcJ7sU= -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/handlers v1.4.0/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.0/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/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20190203031600-7a902570cb17/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.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= 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/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 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/heketi/heketi v9.0.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= -github.com/heketi/rest v0.0.0-20180404230133-aa6a65207413/go.mod h1:BeS3M108VzVlmAue3lv2WcGuPAX94/KN63MUURzbYSI= -github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= -github.com/heketi/utils v0.0.0-20170317161834-435bc5bdfa64/go.mod h1:RYlF4ghFZPPmk2TC5REt5OFwvfb6lzxFWrTWB+qs28s= -github.com/helm/helm-2to3 v0.2.0/go.mod h1:jQUVAWB0bM7zNIqKPIfHFzuFSK0kHYovJrjO+hqcvRk= 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.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -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 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= -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/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/improbable-eng/thanos v0.3.2/go.mod h1:GZewVGILKuJVPNRn7L4Zw+7X96qzFOwj63b22xYGXBE= 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/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= -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 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/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/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jsonnet-bundler/jsonnet-bundler v0.1.0/go.mod h1:YKsSFc9VFhhLITkJS3X2PrRqWG9u2Jq99udTdDjQLfM= -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 h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -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-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= 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/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 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= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/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/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= 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/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= -github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= -github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= -github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= -github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= -github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/maorfr/helm-plugin-utils v0.0.0-20181205064038-588190cb5e3b/go.mod h1:p3gwmRSFqbWw6plBpR0sKl3n3vpu8kX70gvCJKMvvCA= -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/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= -github.com/martinlindhe/base36 v1.0.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8= -github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= 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.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= -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.1/go.mod h1:F9YacGpnZbLQMzuPI0rR6op21YvNu/RjL705LJJpM3k= -github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/mesos/mesos-go v0.0.9/go.mod h1:kPYCMQ9gsOXVAle1OsoY4I1+9kPu8GHkf88aV59fDr4= -github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= -github.com/miekg/dns v0.0.0-20181005163659-0d29b283ac0f/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/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/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= -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/mistifyio/go-zfs v2.1.1+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.0.0/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/hashstructure v1.0.0/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 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= -github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -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/moby/moby v0.7.3-0.20190826074503-38ab9da00309/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= 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/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE= -github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= -github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/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/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/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.4.0/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 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/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.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= 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/runc v1.0.0-rc2.0.20190611121236-6cc515888830/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-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= -github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= -github.com/openshift/api v0.0.0-20190924102528-32369d4db2ad/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= -github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= -github.com/openshift/client-go v0.0.0-20190923180330-3b6373338c9b/go.mod h1:6rzn+JTr7+WYS2E1TExP4gByoABxMznR6y2SnUIkmxk= -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.0.0-20200120235816-80fd2f1a09c9/go.mod h1:S5IdlJvmKkF84K2tBvsrqJbI2FVy03P88R75snpRxJo= -github.com/operator-framework/api v0.3.7-0.20200602203552-431198de9fc2/go.mod h1:Xbje9x0SHmh0nihE21kpesB38vk3cyxnE6JdDS8Jo1Q= -github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5/go.mod h1:zL34MNy92LPutBH5gQK+gGhtgTUlZZX03I2G12vWHF4= -github.com/operator-framework/operator-registry v1.5.1/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= -github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY= -github.com/operator-framework/operator-registry v1.5.7-0.20200121213444-d8e2ec52c19a/go.mod h1:ekexcV4O8YMxdQuPb+Xco7MHfVmRIq7Jvj5e6NU7dHI= -github.com/operator-framework/operator-registry v1.12.6-0.20200605115407-01fa069730e2/go.mod h1:loVINznYhgBIkmv83kU4yee88RS0BBk+hqOw9r4bhJk= -github.com/operator-framework/operator-sdk v0.13.0 h1:AWiKOl6ZeAyQgbGVoD8fNd+eCbFuRWgr4hciaaOEBmE= -github.com/operator-framework/operator-sdk v0.13.0/go.mod h1:XRnicDD4uZCNbJbMXc0B7eyw7hjO4Xzol7FAkWHa1Nc= -github.com/operator-framework/operator-sdk v0.15.2 h1:VlxI0J+HLmMKs5k53drQ/B1AXhyNj0OaD2BbREt8Hnk= -github.com/operator-framework/operator-sdk v0.15.2/go.mod h1:RkC5LpluVONa08ORFIIVCYrEr855xG1/NltRL2jQ8qo= -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.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc= -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 v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4= -github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.2.3/go.mod h1:YnfyPNhBvnY8bW4SGQHCs/aAFhkgySlMZbrF5U0bOVw= -github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M= -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.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= -github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/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/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= -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 h1:BQ53HtBmfOitExawJ6LokA4x8ov/z0SYYb0+HxJfRI8= -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 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI= -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_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= -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 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= 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 h1:kRhiuYSXR3+uv2IbVbZhUxK5zVD/2pp3Gd2PpvPkpEo= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= -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/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-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-20190129233650-316cf8ccfec5/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 h1:CTwfnzjQ+8dS6MhHHu4YswVAD99sL2wjPqP+VkURmKE= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= -github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/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/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.1.1 h1:/ZKcW+ixpq2dOl4yeH4qvACNXnkiDCp5e/F5Tq07X7o= -github.com/prometheus/procfs v0.1.1/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -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/prometheus/tsdb v0.8.0/go.mod h1:fSI0j+IUQrDd7+ZtR9WKIGtoYAYAJUKcKhYLG25tN4g= -github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/robfig/cron v0.0.0-20170526150127-736158dc09e1/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= -github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/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-20191025130928-9355dd04f4b3/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY= -github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc= -github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/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/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/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.0.5/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 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= -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 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -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 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -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 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag 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 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/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/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/technosophos/moniker v0.0.0-20180509230615-a5dbd03a2245/go.mod h1:O1c8HleITsZqzNZDjSNzirUGsMT0oGu9LhHKoJrqO+A= -github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc= -github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= -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/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= -github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= -github.com/vmware/govmomi v0.20.1/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/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/xenolf/lego v0.0.0-20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= -github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= -github.com/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/go-metrics v0.0.0-20150112132944-c25f46c4b940/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/gorelic v0.0.6/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.9.1/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-20180426230345-b49d69b5da94/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-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-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-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 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A= -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-20190911031432-227b76d455e7/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-20191028145041-f83a4685e152 h1:ZC1Xn5A1nlpSmQCIva4bZ3ob3lmhYIefc+GU+DLg1Ow= -golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -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/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/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-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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-20180112015858-5ccada7d0a7b/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-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-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-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-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 h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68= -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 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= -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/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 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/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1268,420 +350,129 @@ 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-20180117170059-2c42eef0765b/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-20181004145325-8469e314837c/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-20190124100055-b90733256f2e/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-20190228124157-a34e9553db1e/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 h1:4y9KwBHBgBNwDbtu44R5o1fdOCQUEXhbk/P4A9WmJq0= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-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-20191005200804-aed5e4c7ecf9/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-20191028164358-195ce5e7f934 h1:u/E0NqCIWRDAo9WCFo6Ko49njPFDLSd3z+X1HgWDMpE= -golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/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-20200106162015-b016eb3dc98e/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/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38= -golang.org/x/sys v0.0.0-20200610111108-226ff32320da/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.20171227012246-e19ae1496984/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/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20170824195420-5d2fd3ccab98/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-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-20190624180213-70d37148ca0c/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-20191018212557-ed542cd5b28a h1:UuQ+70Pi/ZdWHuP4v457pkXeOynTdgd/4enxeIO/98k= -golang.org/x/tools v0.0.0-20191018212557-ed542cd5b28a/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-20191112195655-aa38f8e97acc/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/v2 v2.1.0 h1:Phva6wqu+xR//Njw6iorylFFgn/z547tw5Ne3HZPQ+k= -gomodules.xyz/jsonpatch/v2 v2.1.0/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/gonum v0.0.0-20190710053202-4340aa3071a0/go.mod h1:03dgh78c4UvU1WksguQ/lvJQXbezKQGJSrwwRq5MraQ= -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.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= -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/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= -google.golang.org/appengine v1.6.6/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-20190128161407-8ac453e89fca/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= 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-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -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/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -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= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -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/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/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/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/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.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/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/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.0.0/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 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= 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.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -helm.sh/helm/v3 v3.0.0/go.mod h1:sI7B9yfvMgxtTPMWdk1jSKJ2aa59UyP9qhPydqW6mgo= -helm.sh/helm/v3 v3.0.1/go.mod h1:sI7B9yfvMgxtTPMWdk1jSKJ2aa59UyP9qhPydqW6mgo= -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.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -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-20191016110408-35e52d86657a h1:VVUE9xTCXP6KUPMf92cQmN88orz600ebexcRRaBTepQ= -k8s.io/api v0.0.0-20191016110408-35e52d86657a/go.mod h1:/L5qH+AD540e7Cetbui1tuJeXdmNhO8jM6VkXeDdDhQ= -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.0.0-20191016113550-5357c4baaf65 h1:kThoiqgMsSwBdMK/lPgjtYTsEjbUU9nXCA9DyU3feok= -k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65/go.mod h1:5BINdGqggRXXKnDgpwoJ7PyQH8f+Ypp02fvVNcIFy9s= -k8s.io/apiextensions-apiserver v0.18.0/go.mod h1:18Cwn1Xws4xnWQNC00FLq1E350b9lUF+aOdIWDOZxgo= +k8s.io/api v0.18.6 h1:osqrAXbOQjkKIWDTjrqxWQ3w0GkKb1KA1XkUGHHYpeE= +k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= 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-20191004115801-a2eda9f80ab8 h1:Iieh/ZEgT3BWwbLD5qEKcY06jKuPEl6zC7gPSehoLw4= -k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= -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-20191016112112-5190913f932d/go.mod h1:7OqfAolfWxUM/jJ/HBLyE+cdaWFBUoo5Q5pHgJVj2ws= -k8s.io/apiserver v0.0.0-20191122221311-9d521947b1e1/go.mod h1:RbsZY5zzBIWnz4KbctZsTVjwIuOpTp4Z8oCgFHN4kZQ= -k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= +k8s.io/apimachinery v0.18.6 h1:RtFHnfGNfd1N0LeSrKCUznz5xtUP1elRGvHJbL3Ntag= +k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= 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.0.0-20191016114015-74ad18325ed5/go.mod h1:sDl6WKSQkDM6zS1u9F49a0VooQ3ycYFBFLqd2jf2Xfo= -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.0.0-20191016111102-bec269661e48 h1:C2XVy2z0dV94q9hSSoCuTPp1KOG7IegvbdXuz9VGxoU= -k8s.io/client-go v0.0.0-20191016111102-bec269661e48/go.mod h1:hrwktSwYGI4JK+TJA3dMaFyyvHVi/aLarVHpbs8bgCU= +k8s.io/cli-runtime v0.18.6/go.mod h1:+G/WTNqHgUv636e5y7rhOQ7epUbRXnwmPnhOhD6t9uM= 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/cloud-provider v0.0.0-20191016115326-20453efc2458/go.mod h1:O5SO5xcgxrjJV9EC9R/47RuBpbk5YX9URDBlg++FA5o= -k8s.io/cluster-bootstrap v0.0.0-20191016115129-c07a134afb42/go.mod h1:MzCL6kLExQuHruGaqibd8cugC8nw8QRxm3+lzR5l8SI= -k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= -k8s.io/code-generator v0.0.0-20191004115455-8e001e5d1894 h1:NMYlxaF7rYQJk2E2IyrUhaX81zX24+dmoZdkPw0gJqI= -k8s.io/code-generator v0.0.0-20191004115455-8e001e5d1894/go.mod h1:mJUgkl06XV4kstAnLHAIzJPVCOzVR+ZcfPIv4fUsFCY= -k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= -k8s.io/code-generator v0.18.2 h1:C1Nn2JiMf244CvBDKVPX0W2mZFJkVBg54T8OV7/Imso= +k8s.io/client-go v0.18.6 h1:I+oWqJbibLSGsZj8Xs8F0aWVXJVIoUHWaaJV3kUN/Zw= +k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q= 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-20191016111319-039242c015a9/go.mod h1:SuWowIgd/dtU/m/iv8OD9eOxp3QZBBhTIiWMsBQvKjI= -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/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/component-base v0.18.2 h1:SJweNZAGcUvsypLGNPNGeJ9UgPZQ6+bW+gEHe8uyh/Y= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= -k8s.io/cri-api v0.0.0-20190828162817-608eb1dad4ac/go.mod h1:BvtUaNBr0fEpzb11OfrQiJLsLPtqbmulpo1fPwcpP6Q= -k8s.io/csi-translation-lib v0.0.0-20191016115521-756ffa5af0bd/go.mod h1:lf1VBseeLanBpSXD0N9tuPx1ylI8sA0j6f+rckCKiIk= +k8s.io/component-base v0.18.6/go.mod h1:knSVsibPR5K6EW2XOjEHik6sdU5nCvKMrzMt2D4In14= 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-20191010091904-7fa3014cb28f h1:eW/6wVuHNZgQJmFesyAxu0cvj0WAHHUuGaLbPcmNY3Q= -k8s.io/gengo v0.0.0-20191010091904-7fa3014cb28f/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 h1:RPscN6KhmG54S33L+lr3GS+oD1jmchIU0ll519K6FA4= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= -k8s.io/helm v2.16.1+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI= 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 h1:niceAagH1tzskmaie/icWd7ci1wbG7Bf2c6YGcQv+3c= -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/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.1.0 h1:X3+Mru/L3jy4BI4vcAYkHvL6PyU+QBsuhEqwlI4mgkA= -k8s.io/klog/v2 v2.1.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/kube-aggregator v0.0.0-20191016112429-9587704a8ad4/go.mod h1:+aW0UZgSXdTSHTIFnWnueEuXjOqerDUxGIw6Ygr+vYY= -k8s.io/kube-controller-manager v0.0.0-20191016114939-2b2b218dc1df/go.mod h1:WgrTcPKYAfNa9C0LV1UeK+XqfbSOUH1WGq/vX5UiW40= -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-20190918143330-0270cf2f1c1d h1:Xpe6sK+RY4ZgCTyZ3y273UmFmURhjtoJiwOMbQsXitY= -k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/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-openapi v0.0.0-20200427153329-656914f816f9 h1:5NC2ITmvg8RoxoH0wgmL4zn4VZqXGsKbxrikjaQx6s4= -k8s.io/kube-openapi v0.0.0-20200427153329-656914f816f9/go.mod h1:bfCVj+qXcEaE5SCvzBaqpOySr6tuCcpPKqF6HD8nyCw= -k8s.io/kube-proxy v0.0.0-20191016114407-2e83b6f20229/go.mod h1:2Hxci1uzXO5ipP0h9n2+h18fvNkBTpYlckk5dOPu8zg= -k8s.io/kube-scheduler v0.0.0-20191016114748-65049c67a58b/go.mod h1:BgDUHHC5Wl0xcBUQgo2XEprE5nG5i9tlRR4iNgEFbL0= -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.0.0-20191016120415-2ed914427d51/go.mod h1:gL826ZTIfD4vXTGlmzgTbliCAT9NGiqpCqK2aNYv5MQ= -k8s.io/kubectl v0.18.0/go.mod h1:LOkWx9Z5DXMEg5KtOjHhRiC1fqJPLyCr3KtQgEolCkU= -k8s.io/kubectl v0.18.2/go.mod h1:OdgFa3AlsPKRpFFYE7ICTwulXOcMGXHTc+UKhHKvrb4= -k8s.io/kubelet v0.0.0-20191016114556-7841ed97f1b2/go.mod h1:SBvrtLbuePbJygVXGGCMtWKH07+qrN2dE1iMnteSG8E= -k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/kubernetes v1.16.0/go.mod h1:nlP2zevWKRGKuaaVbKIwozU0Rjg9leVDXkL4YTtjmVs= -k8s.io/kubernetes v1.16.2/go.mod h1:SmhGgKfQ30imqjFVj8AI+iW+zSyFsswNErKYeTfgoH0= -k8s.io/legacy-cloud-providers v0.0.0-20191016115753-cf0698c3a16b/go.mod h1:tKW3pKqdRW8pMveUTpF5pJuCjQxg6a25iLo+Z9BXVH0= -k8s.io/metrics v0.0.0-20191016113814-3b1a734dba6e/go.mod h1:ve7/vMWeY5lEBkZf6Bt5TTbGS3b8wAxwGbdXAsufjRs= -k8s.io/metrics v0.18.0/go.mod h1:8aYTW18koXqjLVKL7Ds05RPMX9ipJZI3mywYvBOxXd4= -k8s.io/metrics v0.18.2/go.mod h1:qga8E7QfYNR9Q89cSCAjinC9pTZ7yv1XSVGUB0vJypg= -k8s.io/repo-infra v0.0.0-20181204233714-00fe14e3d1a3/go.mod h1:+G1xBfZDfVFsm1Tj/HNCvg4QqWx8rJ2Fxpqr1rqp/gQ= -k8s.io/sample-apiserver v0.0.0-20191016112829-06bb3c9d77c9/go.mod h1:sXltHZrQa4jdKL14nOFRRUhhzpmbnRF0qGuAhRQbaxc= -k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191010214722-8d271d903fe4 h1:Gi+/O1saihwDqnlmC8Vhv1M5Sp4+rbOmK9TbsLn8ZEA= -k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kubectl v0.18.6 h1:IFPNuLPkZ59vSGQzynXY8XGz9yuOSRpkJupnobdYvO4= +k8s.io/kubectl v0.18.6/go.mod h1:3TLzFOrF9h4mlRPAvdNkDbs5NWspN4e0EnPnEB41CGo= +k8s.io/metrics v0.18.6/go.mod h1:iAwGeabusQNO3duHDM7BBExTUB8L+iq8PM7N9EtQw6g= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE= -k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -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.1/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= -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.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg= -sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= 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.2/go.mod h1:8SNGuj163x/sMwydREj7ld5mIMJu1cDanIfnx6xsU70= -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/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM= -sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= 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= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt new file mode 100644 index 0000000000..28a7641a8b --- /dev/null +++ b/hack/boilerplate.go.txt @@ -0,0 +1,13 @@ +// Copyright The OpenTelemetry Authors +// +// 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. diff --git a/hack/install-kubebuilder.sh b/hack/install-kubebuilder.sh new file mode 100755 index 0000000000..0befb55dd8 --- /dev/null +++ b/hack/install-kubebuilder.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +os=$(go env GOOS) +arch=$(go env GOARCH) +curl -L https://go.kubebuilder.io/dl/2.3.1/${os}/${arch} | tar -xz -C /tmp/ +sudo mv /tmp/kubebuilder_2.3.1_${os}_${arch} /usr/local/kubebuilder +export PATH=$PATH:/usr/local/kubebuilder/bin diff --git a/internal/config/main.go b/internal/config/main.go new file mode 100644 index 0000000000..7fc478ea7c --- /dev/null +++ b/internal/config/main.go @@ -0,0 +1,64 @@ +// Copyright The OpenTelemetry Authors +// +// 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 config + +import ( + "fmt" + + "github.com/open-telemetry/opentelemetry-operator/internal/version" + "github.com/spf13/pflag" +) + +// Config holds the static configuration for this operator +type Config struct { + v version.Version + collectorImage string + collectorConfigMapEntry string +} + +// DefaultConfig builds a new configuration populated with the default, immutable values +func DefaultConfig() Config { + return WithVersion(version.Get()) +} + +// WithVersion builds a new configuration using the provided version object +func WithVersion(v version.Version) Config { + return Config{ + v: v, + collectorConfigMapEntry: "collector.yaml", + } +} + +// FlagSet binds the flags to the user-modifiable values of the operator's configuration +func (c *Config) FlagSet() *pflag.FlagSet { + fs := pflag.NewFlagSet("opentelemetry-operator", pflag.ExitOnError) + pflag.StringVar(&c.collectorImage, + "otelcol-image", + fmt.Sprintf("quay.io/opentelemetry/opentelemetry-collector:v%s", c.v.OpenTelemetryCollector), + "The default image to use for OpenTelemetry Collector when not specified in the individual custom resource (CR)", + ) + + return fs +} + +// CollectorImage represents the flag to override the OpenTelemetry Collector container image. +func (c *Config) CollectorImage() string { + return c.collectorImage +} + +// CollectorConfigMapEntry represents the configuration file name for the collector. Immutable. +func (c *Config) CollectorConfigMapEntry() string { + return c.collectorConfigMapEntry +} diff --git a/pkg/version/main.go b/internal/version/main.go similarity index 69% rename from pkg/version/main.go rename to internal/version/main.go index e8652a220c..7036e7d525 100644 --- a/pkg/version/main.go +++ b/internal/version/main.go @@ -3,8 +3,6 @@ package version import ( "fmt" "runtime" - - sdkVersion "github.com/operator-framework/operator-sdk/version" ) var ( @@ -19,7 +17,6 @@ type Version struct { BuildDate string `json:"build-date"` OpenTelemetryCollector string `json:"opentelemetry-collector-version"` Go string `json:"go-version"` - OperatorSdk string `json:"operator-sdk-version"` } // Get returns the Version object with the relevant information @@ -27,25 +24,23 @@ func Get() Version { return Version{ Operator: version, BuildDate: buildDate, - OpenTelemetryCollector: DefaultOpenTelemetryCollector(), + OpenTelemetryCollector: OpenTelemetryCollector(), Go: runtime.Version(), - OperatorSdk: sdkVersion.Version, } } func (v Version) String() string { return fmt.Sprintf( - "Version(Operator='%v', BuildDate='%v', OpenTelemetryCollector='%v', Go='%v', OperatorSDK='%v')", + "Version(Operator='%v', BuildDate='%v', OpenTelemetryCollector='%v', Go='%v')", v.Operator, v.BuildDate, v.OpenTelemetryCollector, v.Go, - v.OperatorSdk, ) } -// DefaultOpenTelemetryCollector returns the default OpenTelemetryCollector to use when no versions are specified via CLI or configuration -func DefaultOpenTelemetryCollector() string { +// OpenTelemetryCollector returns the default OpenTelemetryCollector to use when no versions are specified via CLI or configuration +func OpenTelemetryCollector() string { if len(otelCol) > 0 { // this should always be set, as it's specified during the build return otelCol diff --git a/internal/version/main_test.go b/internal/version/main_test.go new file mode 100644 index 0000000000..cb2ec2b0d6 --- /dev/null +++ b/internal/version/main_test.go @@ -0,0 +1,23 @@ +package version + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Version management", func() { + It("should have a fallback version", func() { + Expect(OpenTelemetryCollector()).To(Equal("0.0.0")) + }) + + It("should use a version set during the build", func() { + // prepare + otelCol = "0.0.2" // set during the build + defer func() { + otelCol = "" + }() + + Expect(OpenTelemetryCollector()).To(Equal(otelCol)) + Expect(Get()).To(ContainSubstring(otelCol)) + }) +}) diff --git a/internal/version/version_suite_test.go b/internal/version/version_suite_test.go new file mode 100644 index 0000000000..fa25d588f4 --- /dev/null +++ b/internal/version/version_suite_test.go @@ -0,0 +1,13 @@ +package version_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestVersion(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Version Suite") +} diff --git a/main.go b/main.go new file mode 100644 index 0000000000..4e4840e257 --- /dev/null +++ b/main.go @@ -0,0 +1,136 @@ +// Copyright The OpenTelemetry Authors +// +// 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" + "flag" + "os" + "runtime" + "strings" + + "github.com/spf13/pflag" + k8sruntime "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/cache" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + "sigs.k8s.io/controller-runtime/pkg/manager" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/controllers" + "github.com/open-telemetry/opentelemetry-operator/internal/config" + "github.com/open-telemetry/opentelemetry-operator/internal/version" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/upgrade" + // +kubebuilder:scaffold:imports +) + +var ( + scheme = k8sruntime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(v1alpha1.AddToScheme(scheme)) + // +kubebuilder:scaffold:scheme +} + +func main() { + logger := zap.New(zap.UseDevMode(true)) + + v := version.Get() + logger.Info("Starting the OpenTelemetry Operator", + "opentelemetry-operator", v.Operator, + "opentelemetry-collector", v.OpenTelemetryCollector, + "build-date", v.BuildDate, + "go-version", v.Go, + "go-arch", runtime.GOARCH, + "go-os", runtime.GOOS, + ) + + // registers any flags that underlying libraries might use + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + + var metricsAddr string + var enableLeaderElection bool + pflag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") + pflag.BoolVar(&enableLeaderElection, "enable-leader-election", false, + "Enable leader election for controller manager. "+ + "Enabling this will ensure there is only one active controller manager.") + + // Add flags related to this operator + config := config.WithVersion(v) + pflag.CommandLine.AddFlagSet(config.FlagSet()) + + pflag.Parse() + + ctrl.SetLogger(logger) + + watchNamespace, found := os.LookupEnv("WATCH_NAMESPACE") + if found { + setupLog.Info("watching namespace(s)", "namespaces", watchNamespace) + } else { + setupLog.Info("the env var WATCH_NAMESPACE isn't set, watching all namespaces") + } + + mgrOptions := ctrl.Options{ + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Port: 9443, + LeaderElection: enableLeaderElection, + LeaderElectionID: "9f7554c3.opentelemetry.io", + Namespace: watchNamespace, + } + + if strings.Contains(watchNamespace, ",") { + mgrOptions.Namespace = "" + mgrOptions.NewCache = cache.MultiNamespacedCacheBuilder(strings.Split(watchNamespace, ",")) + } + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), mgrOptions) + if err != nil { + setupLog.Error(err, "unable to start manager") + os.Exit(1) + } + + // adds the upgrade mechanism to be executed once the manager is ready + err = mgr.Add(manager.RunnableFunc(func(<-chan struct{}) error { + return upgrade.ManagedInstances(context.Background(), ctrl.Log.WithName("upgrade"), mgr.GetClient()) + })) + if err != nil { + setupLog.Error(err, "failed to upgrade managed instances") + } + + if err = controllers.NewReconciler(controllers.Params{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("OpenTelemetryCollector"), + Scheme: mgr.GetScheme(), + Config: config, + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "OpenTelemetryCollector") + os.Exit(1) + } + // +kubebuilder:scaffold:builder + + 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/adapters/config_from.go b/pkg/adapters/config_from.go deleted file mode 100644 index 1d7380fdde..0000000000 --- a/pkg/adapters/config_from.go +++ /dev/null @@ -1,42 +0,0 @@ -package adapters - -import ( - "context" - "errors" - - "gopkg.in/yaml.v2" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -var ( - // ErrNoInstance represents an error when an instance isn't available in the context - ErrNoInstance = errors.New("couldn't get the opentelemetry-collector instance from the context") - - // ErrInvalidYAML represents an error in the format of the configuration file - ErrInvalidYAML = errors.New("couldn't parse the opentelemetry-collector configuration to assemble a list of ports for the service") -) - -// ConfigFromCtx extracts a configuration map from the given context. -// If an instance isn't available in the context, ErrNoInstance is returned. -// If the .Spec.Config isn't a valid YAML, ErrInvalidYAML is returned. -func ConfigFromCtx(ctx context.Context) (map[interface{}]interface{}, error) { - switch instance := ctx.Value(opentelemetry.ContextInstance).(type) { - case *v1alpha1.OpenTelemetryCollector: - return ConfigFromString(instance.Spec.Config) - default: - return nil, ErrNoInstance - } -} - -// ConfigFromString extracts a configuration map from the given string. -// If the given string isn't a valid YAML, ErrInvalidYAML is returned. -func ConfigFromString(configStr string) (map[interface{}]interface{}, error) { - config := make(map[interface{}]interface{}) - if err := yaml.Unmarshal([]byte(configStr), &config); err != nil { - return nil, ErrInvalidYAML - } - - return config, nil -} diff --git a/pkg/adapters/config_from_test.go b/pkg/adapters/config_from_test.go deleted file mode 100644 index a5a167a419..0000000000 --- a/pkg/adapters/config_from_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package adapters - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -func TestConfigFromCtx(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{} - instance.Spec.Config = "mykey: myval" - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, instance) - - // test - config, err := ConfigFromCtx(ctx) - - // verify - assert.NoError(t, err) - assert.EqualValues(t, "myval", config["mykey"]) -} - -func TestConfigFromCtxNoContext(t *testing.T) { - // test - config, err := ConfigFromCtx(context.Background()) - - // verify - assert.Equal(t, ErrNoInstance, err) - assert.Nil(t, config) -} - -func TestConfigFromStringInvalidYAML(t *testing.T) { - // test - config, err := ConfigFromString("🦄") - - // verify - assert.Equal(t, ErrInvalidYAML, err) - assert.Nil(t, config) -} - -func TestConfigFromStringEmptyMap(t *testing.T) { - // test - config, err := ConfigFromString("") - - // verify - assert.Nil(t, err) - assert.Len(t, config, 0) -} diff --git a/pkg/adapters/config_to_ports_test.go b/pkg/adapters/config_to_ports_test.go deleted file mode 100644 index e877bb5b1a..0000000000 --- a/pkg/adapters/config_to_ports_test.go +++ /dev/null @@ -1,177 +0,0 @@ -package adapters - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/parser" -) - -var ( - logger = logf.Log.WithName("unit-tests") - ctxWithLogger = context.WithValue(context.Background(), opentelemetry.ContextLogger, logger) -) - -func TestExtractPortsFromConfig(t *testing.T) { - // prepare - configStr := `receivers: - examplereceiver: - endpoint: "0.0.0.0:12345" - examplereceiver/settings: - endpoint: "0.0.0.0:12346" - examplereceiver/invalid-ignored: - endpoint: "0.0.0.0" - examplereceiver/invalid-not-number: - endpoint: "0.0.0.0:not-number" - examplereceiver/without-endpoint: - notendpoint: "0.0.0.0:12347" - jaeger: - protocols: - grpc: - thrift_compact: - thrift_binary: - endpoint: 0.0.0.0:6833 - jaeger/custom: - protocols: - thrift_http: - endpoint: 0.0.0.0:15268 -` - - // test - config, err := ConfigFromString(configStr) - require.NoError(t, err) - ports, err := ConfigToReceiverPorts(ctxWithLogger, config) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 6) - - expectedPorts := map[int32]bool{} - expectedPorts[int32(12345)] = false - expectedPorts[int32(12346)] = false - expectedPorts[int32(14250)] = false - expectedPorts[int32(6831)] = false - expectedPorts[int32(6833)] = false - expectedPorts[int32(15268)] = false - - expectedNames := map[string]bool{} - expectedNames["examplereceiver"] = false - expectedNames["examplereceiver-settings"] = false - expectedNames["jaeger-grpc"] = false - expectedNames["jaeger-thrift-compact"] = false - expectedNames["jaeger-thrift-binary"] = false - expectedNames["jaeger-custom-thrift-http"] = false - - // make sure we only have the ports in the set - for _, port := range ports { - assert.Contains(t, expectedPorts, port.Port) - assert.Contains(t, expectedNames, port.Name) - expectedPorts[port.Port] = true - expectedNames[port.Name] = true - } - - // and make sure all the ports from the set are there - for _, val := range expectedPorts { - assert.True(t, val) - } -} - -func TestNoPortsParsed(t *testing.T) { - for _, tt := range []struct { - config string - expected error - }{ - // prepare - { - config: "", - expected: ErrNoReceivers, - }, - { - config: "receivers: some-string", - expected: ErrReceiversNotAMap, - }, - } { - config, err := ConfigFromString(tt.config) - require.NoError(t, err) - - // test - ports, err := ConfigToReceiverPorts(ctxWithLogger, config) - - // verify - assert.Equal(t, tt.expected, err) - assert.Nil(t, ports) - } -} - -func TestInvalidReceiver(t *testing.T) { - for _, tt := range []string{ - // the receiver isn't a map, can't have an endpoint - "receivers:\n some-receiver: string", - - // the receiver's endpoint isn't a string, can't parse the port from it - "receivers:\n some-receiver:\n endpoint: 123", - } { - // test - config, err := ConfigFromString(tt) - require.NoError(t, err) - ports, err := ConfigToReceiverPorts(ctxWithLogger, config) - - // verify - assert.NoError(t, err) - assert.NotNil(t, ports) - assert.Len(t, ports, 0) - } - -} - -func TestParserFailed(t *testing.T) { - // prepare - mockParserCalled := false - mockParser := &mockParser{ - portsFunc: func(context.Context) ([]v1.ServicePort, error) { - mockParserCalled = true - return nil, errors.New("mocked error") - }, - } - parser.Register("mock", func(name string, config map[interface{}]interface{}) parser.ReceiverParser { - return mockParser - }) - - config := map[interface{}]interface{}{ - "receivers": map[interface{}]interface{}{ - "mock": map[interface{}]interface{}{}, - }, - } - - // test - ports, err := ConfigToReceiverPorts(ctxWithLogger, config) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 0) - assert.True(t, mockParserCalled) -} - -type mockParser struct { - portsFunc func(context.Context) ([]corev1.ServicePort, error) -} - -func (m *mockParser) Ports(ctx context.Context) ([]corev1.ServicePort, error) { - if m.portsFunc != nil { - return m.portsFunc(ctx) - } - - return nil, nil -} - -func (m *mockParser) ParserName() string { - return "__mock-adapters" -} diff --git a/pkg/apis/addtoscheme_opentelemetry_v1alpha1.go b/pkg/apis/addtoscheme_opentelemetry_v1alpha1.go deleted file mode 100644 index ee6c25b285..0000000000 --- a/pkg/apis/addtoscheme_opentelemetry_v1alpha1.go +++ /dev/null @@ -1,10 +0,0 @@ -package apis - -import ( - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/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/apis.go b/pkg/apis/apis.go deleted file mode 100644 index 07dc961644..0000000000 --- a/pkg/apis/apis.go +++ /dev/null @@ -1,13 +0,0 @@ -package apis - -import ( - "k8s.io/apimachinery/pkg/runtime" -) - -// 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) -} diff --git a/pkg/apis/empty_test.go b/pkg/apis/empty_test.go deleted file mode 100644 index 03fd21c534..0000000000 --- a/pkg/apis/empty_test.go +++ /dev/null @@ -1,2 +0,0 @@ -// this file exists to force the coverage tool to count this directory -package apis diff --git a/pkg/apis/opentelemetry/const.go b/pkg/apis/opentelemetry/const.go deleted file mode 100644 index 709896632a..0000000000 --- a/pkg/apis/opentelemetry/const.go +++ /dev/null @@ -1,32 +0,0 @@ -package opentelemetry - -type ( - // ContextEntry represents a key in the context map - ContextEntry string - - // Mode represents how the collector should be deployed (deployment vs. daemonset) - Mode string -) - -const ( - // ContextInstance is the OpenTelemetryCollector CR (instance) that is the current target of the reconciliation - ContextInstance ContextEntry = "__instance" - - // ContextLogger represents the context entry for the logger instance to be used for context-dependent log entries - ContextLogger ContextEntry = "__logger" - - // ModeDaemonSet specifies that the collector should be deployed as a Kubernetes DaemonSet - ModeDaemonSet Mode = "daemonset" - - // ModeDeployment specifies that the collector should be deployed as a Kubernetes Deployment - ModeDeployment Mode = "deployment" - - // CollectorConfigMapEntry represents the configuration file name for the collector - CollectorConfigMapEntry = "collector.yaml" - - // OtelColImageConfigKey represents the key to override the OpenTelemetry Collector container image - OtelColImageConfigKey = "otelcol-image" - - // SvcMonitorAvailable represents the key that indicates whether a ServiceMonitor CRD is known to the cluster - SvcMonitorAvailable = "svc-monitor-avail" -) diff --git a/pkg/apis/opentelemetry/empty_test.go b/pkg/apis/opentelemetry/empty_test.go deleted file mode 100644 index 69082cbb7e..0000000000 --- a/pkg/apis/opentelemetry/empty_test.go +++ /dev/null @@ -1,2 +0,0 @@ -// this file exists to force the coverage tool to count this directory -package opentelemetry diff --git a/pkg/apis/opentelemetry/flagset.go b/pkg/apis/opentelemetry/flagset.go deleted file mode 100644 index ee015ae483..0000000000 --- a/pkg/apis/opentelemetry/flagset.go +++ /dev/null @@ -1,42 +0,0 @@ -package opentelemetry - -import ( - "fmt" - "sync" - - "github.com/spf13/pflag" - "github.com/spf13/viper" - - "github.com/open-telemetry/opentelemetry-operator/pkg/version" -) - -var ( - mu sync.Mutex - fs *pflag.FlagSet -) - -// FlagSet returns this operator's flags -func FlagSet() *pflag.FlagSet { - if nil == fs { - mu.Lock() - defer mu.Unlock() - - otelColVersion := version.Get().OpenTelemetryCollector - - fs = pflag.NewFlagSet("opentelemetry-operator", pflag.ExitOnError) - fs.String( - OtelColImageConfigKey, - fmt.Sprintf("quay.io/opentelemetry/opentelemetry-collector:v%s", otelColVersion), - "The default image to use for OpenTelemetry Collector when not specified in the individual custom resource (CR)", - ) - // #nosec G104 (CWE-703): Errors unhandled. - viper.BindPFlag(OtelColImageConfigKey, fs.Lookup(OtelColImageConfigKey)) - } - - return fs -} - -// ResetFlagSet will set the cached flagset to nil -func ResetFlagSet() { - fs = nil -} diff --git a/pkg/apis/opentelemetry/v1alpha1/doc.go b/pkg/apis/opentelemetry/v1alpha1/doc.go deleted file mode 100644 index 961c2544a5..0000000000 --- a/pkg/apis/opentelemetry/v1alpha1/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Package v1alpha1 contains API Schema definitions for the opentelemetry v1alpha1 API group -// +k8s:deepcopy-gen=package,register -// +groupName=opentelemetry.io -package v1alpha1 diff --git a/pkg/apis/opentelemetry/v1alpha1/empty_test.go b/pkg/apis/opentelemetry/v1alpha1/empty_test.go deleted file mode 100644 index 64da128b52..0000000000 --- a/pkg/apis/opentelemetry/v1alpha1/empty_test.go +++ /dev/null @@ -1,2 +0,0 @@ -// this file exists to force the coverage tool to count this directory -package v1alpha1 diff --git a/pkg/apis/opentelemetry/v1alpha1/register.go b/pkg/apis/opentelemetry/v1alpha1/register.go deleted file mode 100644 index 1f79cf0f03..0000000000 --- a/pkg/apis/opentelemetry/v1alpha1/register.go +++ /dev/null @@ -1,17 +0,0 @@ -// Package v1alpha1 contains API Schema definitions for the opentelemetry v1alpha1 API group -// +k8s:deepcopy-gen=package,register -// +groupName=opentelemetry.io -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/runtime/scheme" -) - -var ( - // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: "opentelemetry.io", Version: "v1alpha1"} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} -) diff --git a/pkg/apis/opentelemetry/v1alpha1/zz_generated.openapi.go b/pkg/apis/opentelemetry/v1alpha1/zz_generated.openapi.go deleted file mode 100644 index fe089ef1df..0000000000 --- a/pkg/apis/opentelemetry/v1alpha1/zz_generated.openapi.go +++ /dev/null @@ -1,209 +0,0 @@ -// +build !ignore_autogenerated - -// Code generated by openapi-gen. DO NOT EDIT. - -// This file was autogenerated by openapi-gen. Do not edit it manually! - -package v1alpha1 - -import ( - spec "github.com/go-openapi/spec" - common "k8s.io/kube-openapi/pkg/common" -) - -func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { - return map[string]common.OpenAPIDefinition{ - "./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryCollector": schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryCollector(ref), - "./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryCollectorSpec": schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryCollectorSpec(ref), - "./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryCollectorStatus": schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryCollectorStatus(ref), - } -} - -func schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryCollector(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "OpenTelemetryCollector is the Schema for the opentelemetrycollectors API", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - 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{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), - }, - }, - "spec": { - SchemaProps: spec.SchemaProps{ - Ref: ref("./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryCollectorSpec"), - }, - }, - "status": { - SchemaProps: spec.SchemaProps{ - Ref: ref("./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryCollectorStatus"), - }, - }, - }, - }, - }, - Dependencies: []string{ - "./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryCollectorSpec", "./pkg/apis/opentelemetry/v1alpha1.OpenTelemetryCollectorStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, - } -} - -func schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryCollectorSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "OpenTelemetryCollectorSpec defines the desired state of OpenTelemetryCollector", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "config": { - SchemaProps: spec.SchemaProps{ - Description: "Config is the raw JSON to be used as the collector's configuration. Refer to the OpenTelemetry Collector documentation for details.", - Type: []string{"string"}, - Format: "", - }, - }, - "args": { - SchemaProps: spec.SchemaProps{ - Description: "Args is the set of arguments to pass to the OpenTelemetry Collector binary", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "replicas": { - SchemaProps: spec.SchemaProps{ - Description: "Replicas is the number of pod instances for the underlying OpenTelemetry Collector", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "image": { - SchemaProps: spec.SchemaProps{ - Description: "Image indicates the container image to use for the OpenTelemetry Collector.", - Type: []string{"string"}, - Format: "", - }, - }, - "mode": { - SchemaProps: spec.SchemaProps{ - Description: "Mode represents how the collector should be deployed (deployment vs. daemonset)", - Type: []string{"string"}, - Format: "", - }, - }, - "serviceAccount": { - SchemaProps: spec.SchemaProps{ - Description: "ServiceAccount indicates the name of an existing service account to use with this instance.", - Type: []string{"string"}, - Format: "", - }, - }, - "volumeMounts": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "VolumeMounts represents the mount points to use in the underlying collector deployment(s)", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/api/core/v1.VolumeMount"), - }, - }, - }, - }, - }, - "volumes": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "Volumes represents which volumes to use in the underlying collector deployment(s).", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/api/core/v1.Volume"), - }, - }, - }, - }, - }, - "ports": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, - SchemaProps: spec.SchemaProps{ - Description: "Ports allows a set of ports to be exposed by the underlying v1.Service. By default, the operator will attempt to infer the required ports by parsing the .Spec.Config property but this property can be used to open aditional ports that can't be inferred by the operator, like for custom receivers.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Ref: ref("k8s.io/api/core/v1.ServicePort"), - }, - }, - }, - }, - }, - }, - }, - }, - Dependencies: []string{ - "k8s.io/api/core/v1.ServicePort", "k8s.io/api/core/v1.Volume", "k8s.io/api/core/v1.VolumeMount"}, - } -} - -func schema_pkg_apis_opentelemetry_v1alpha1_OpenTelemetryCollectorStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Description: "OpenTelemetryCollectorStatus defines the observed state of OpenTelemetryCollector", - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "replicas": { - SchemaProps: spec.SchemaProps{ - Type: []string{"integer"}, - Format: "int32", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"replicas", "version"}, - }, - }, - } -} diff --git a/pkg/client/clientset.go b/pkg/client/clientset.go deleted file mode 100644 index a9f3742308..0000000000 --- a/pkg/client/clientset.go +++ /dev/null @@ -1,40 +0,0 @@ -package client - -import ( - monclient "github.com/coreos/prometheus-operator/pkg/client/versioned" - "k8s.io/client-go/kubernetes" - "sigs.k8s.io/controller-runtime/pkg/manager" - - otclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned" -) - -// Clientset holds all the clients that the reconciler might need to hold -type Clientset struct { - Kubernetes kubernetes.Interface - Monitoring monclient.Interface - OpenTelemetry otclient.Interface -} - -// ForManager returns a Clientset based on the information from the given manager -func ForManager(mgr manager.Manager) (*Clientset, error) { - cl, err := kubernetes.NewForConfig(mgr.GetConfig()) - if err != nil { - return nil, err - } - - monclient, err := monclient.NewForConfig(mgr.GetConfig()) - if err != nil { - return nil, err - } - - otclient, err := otclient.NewForConfig(mgr.GetConfig()) - if err != nil { - return nil, err - } - - return &Clientset{ - Kubernetes: cl, - Monitoring: monclient, - OpenTelemetry: otclient, - }, nil -} diff --git a/pkg/client/versioned/clientset.go b/pkg/client/versioned/clientset.go deleted file mode 100644 index 8b9733aa49..0000000000 --- a/pkg/client/versioned/clientset.go +++ /dev/null @@ -1,82 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package versioned - -import ( - "fmt" - - discovery "k8s.io/client-go/discovery" - rest "k8s.io/client-go/rest" - flowcontrol "k8s.io/client-go/util/flowcontrol" - - opentelemetryv1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/typed/opentelemetry/v1alpha1" -) - -type Interface interface { - Discovery() discovery.DiscoveryInterface - OpentelemetryV1alpha1() opentelemetryv1alpha1.OpentelemetryV1alpha1Interface -} - -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. -type Clientset struct { - *discovery.DiscoveryClient - opentelemetryV1alpha1 *opentelemetryv1alpha1.OpentelemetryV1alpha1Client -} - -// OpentelemetryV1alpha1 retrieves the OpentelemetryV1alpha1Client -func (c *Clientset) OpentelemetryV1alpha1() opentelemetryv1alpha1.OpentelemetryV1alpha1Interface { - return c.opentelemetryV1alpha1 -} - -// Discovery retrieves the DiscoveryClient -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - if c == nil { - return nil - } - return c.DiscoveryClient -} - -// NewForConfig creates a new Clientset for the given config. -// If config's RateLimiter is not set and QPS and Burst are acceptable, -// NewForConfig will generate a rate-limiter in configShallowCopy. -func NewForConfig(c *rest.Config) (*Clientset, error) { - configShallowCopy := *c - if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { - if configShallowCopy.Burst <= 0 { - return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") - } - configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) - } - var cs Clientset - var err error - cs.opentelemetryV1alpha1, err = opentelemetryv1alpha1.NewForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - - cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) - if err != nil { - return nil, err - } - return &cs, nil -} - -// NewForConfigOrDie creates a new Clientset for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *Clientset { - var cs Clientset - cs.opentelemetryV1alpha1 = opentelemetryv1alpha1.NewForConfigOrDie(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) - return &cs -} - -// New creates a new Clientset for the given RESTClient. -func New(c rest.Interface) *Clientset { - var cs Clientset - cs.opentelemetryV1alpha1 = opentelemetryv1alpha1.New(c) - - cs.DiscoveryClient = discovery.NewDiscoveryClient(c) - return &cs -} diff --git a/pkg/client/versioned/doc.go b/pkg/client/versioned/doc.go deleted file mode 100644 index 0e0c2a8900..0000000000 --- a/pkg/client/versioned/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated clientset. -package versioned diff --git a/pkg/client/versioned/fake/clientset_generated.go b/pkg/client/versioned/fake/clientset_generated.go deleted file mode 100644 index 4a15bac24d..0000000000 --- a/pkg/client/versioned/fake/clientset_generated.go +++ /dev/null @@ -1,67 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/discovery" - fakediscovery "k8s.io/client-go/discovery/fake" - "k8s.io/client-go/testing" - - clientset "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned" - opentelemetryv1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/typed/opentelemetry/v1alpha1" - fakeopentelemetryv1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake" -) - -// NewSimpleClientset returns a clientset that will respond with the provided objects. -// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, -// without applying any validations and/or defaults. It shouldn't be considered a replacement -// for a real clientset and is mostly useful in simple unit tests. -func NewSimpleClientset(objects ...runtime.Object) *Clientset { - o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) - for _, obj := range objects { - if err := o.Add(obj); err != nil { - panic(err) - } - } - - cs := &Clientset{tracker: o} - cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} - cs.AddReactor("*", "*", testing.ObjectReaction(o)) - cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { - gvr := action.GetResource() - ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) - if err != nil { - return false, nil, err - } - return true, watch, nil - }) - - return cs -} - -// Clientset implements clientset.Interface. Meant to be embedded into a -// struct to get a default implementation. This makes faking out just the method -// you want to test easier. -type Clientset struct { - testing.Fake - discovery *fakediscovery.FakeDiscovery - tracker testing.ObjectTracker -} - -func (c *Clientset) Discovery() discovery.DiscoveryInterface { - return c.discovery -} - -func (c *Clientset) Tracker() testing.ObjectTracker { - return c.tracker -} - -var _ clientset.Interface = &Clientset{} - -// OpentelemetryV1alpha1 retrieves the OpentelemetryV1alpha1Client -func (c *Clientset) OpentelemetryV1alpha1() opentelemetryv1alpha1.OpentelemetryV1alpha1Interface { - return &fakeopentelemetryv1alpha1.FakeOpentelemetryV1alpha1{Fake: &c.Fake} -} diff --git a/pkg/client/versioned/fake/doc.go b/pkg/client/versioned/fake/doc.go deleted file mode 100644 index 3630ed1cd1..0000000000 --- a/pkg/client/versioned/fake/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated fake clientset. -package fake diff --git a/pkg/client/versioned/fake/register.go b/pkg/client/versioned/fake/register.go deleted file mode 100644 index 875ddd7680..0000000000 --- a/pkg/client/versioned/fake/register.go +++ /dev/null @@ -1,41 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - - opentelemetryv1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -var scheme = runtime.NewScheme() -var codecs = serializer.NewCodecFactory(scheme) -var parameterCodec = runtime.NewParameterCodec(scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - opentelemetryv1alpha1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(scheme)) -} diff --git a/pkg/client/versioned/scheme/doc.go b/pkg/client/versioned/scheme/doc.go deleted file mode 100644 index 14db57a58f..0000000000 --- a/pkg/client/versioned/scheme/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -// This package contains the scheme of the automatically generated clientset. -package scheme diff --git a/pkg/client/versioned/scheme/register.go b/pkg/client/versioned/scheme/register.go deleted file mode 100644 index e16005b08f..0000000000 --- a/pkg/client/versioned/scheme/register.go +++ /dev/null @@ -1,41 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package scheme - -import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - schema "k8s.io/apimachinery/pkg/runtime/schema" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - - opentelemetryv1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -var Scheme = runtime.NewScheme() -var Codecs = serializer.NewCodecFactory(Scheme) -var ParameterCodec = runtime.NewParameterCodec(Scheme) -var localSchemeBuilder = runtime.SchemeBuilder{ - opentelemetryv1alpha1.AddToScheme, -} - -// AddToScheme adds all types of this clientset into the given scheme. This allows composition -// of clientsets, like in: -// -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) -// -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) -// -// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types -// correctly. -var AddToScheme = localSchemeBuilder.AddToScheme - -func init() { - v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(AddToScheme(Scheme)) -} diff --git a/pkg/client/versioned/typed/opentelemetry/v1alpha1/doc.go b/pkg/client/versioned/typed/opentelemetry/v1alpha1/doc.go deleted file mode 100644 index 93a7ca4e0e..0000000000 --- a/pkg/client/versioned/typed/opentelemetry/v1alpha1/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -// This package has the automatically generated typed clients. -package v1alpha1 diff --git a/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/doc.go b/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/doc.go deleted file mode 100644 index 2b5ba4c8e4..0000000000 --- a/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -// Package fake has the automatically generated clients. -package fake diff --git a/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/fake_opentelemetry_client.go b/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/fake_opentelemetry_client.go deleted file mode 100644 index ea6db0066a..0000000000 --- a/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/fake_opentelemetry_client.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" - - v1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/typed/opentelemetry/v1alpha1" -) - -type FakeOpentelemetryV1alpha1 struct { - *testing.Fake -} - -func (c *FakeOpentelemetryV1alpha1) OpenTelemetryCollectors(namespace string) v1alpha1.OpenTelemetryCollectorInterface { - return &FakeOpenTelemetryCollectors{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeOpentelemetryV1alpha1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/fake_opentelemetrycollector.go b/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/fake_opentelemetrycollector.go deleted file mode 100644 index 4b3c5988d8..0000000000 --- a/pkg/client/versioned/typed/opentelemetry/v1alpha1/fake/fake_opentelemetrycollector.go +++ /dev/null @@ -1,127 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - "context" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - - v1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// FakeOpenTelemetryCollectors implements OpenTelemetryCollectorInterface -type FakeOpenTelemetryCollectors struct { - Fake *FakeOpentelemetryV1alpha1 - ns string -} - -var opentelemetrycollectorsResource = schema.GroupVersionResource{Group: "opentelemetry.io", Version: "v1alpha1", Resource: "opentelemetrycollectors"} - -var opentelemetrycollectorsKind = schema.GroupVersionKind{Group: "opentelemetry.io", Version: "v1alpha1", Kind: "OpenTelemetryCollector"} - -// Get takes name of the openTelemetryCollector, and returns the corresponding openTelemetryCollector object, and an error if there is any. -func (c *FakeOpenTelemetryCollectors) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OpenTelemetryCollector, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(opentelemetrycollectorsResource, c.ns, name), &v1alpha1.OpenTelemetryCollector{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.OpenTelemetryCollector), err -} - -// List takes label and field selectors, and returns the list of OpenTelemetryCollectors that match those selectors. -func (c *FakeOpenTelemetryCollectors) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OpenTelemetryCollectorList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(opentelemetrycollectorsResource, opentelemetrycollectorsKind, c.ns, opts), &v1alpha1.OpenTelemetryCollectorList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.OpenTelemetryCollectorList{ListMeta: obj.(*v1alpha1.OpenTelemetryCollectorList).ListMeta} - for _, item := range obj.(*v1alpha1.OpenTelemetryCollectorList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested openTelemetryCollectors. -func (c *FakeOpenTelemetryCollectors) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(opentelemetrycollectorsResource, c.ns, opts)) - -} - -// Create takes the representation of a openTelemetryCollector and creates it. Returns the server's representation of the openTelemetryCollector, and an error, if there is any. -func (c *FakeOpenTelemetryCollectors) Create(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.CreateOptions) (result *v1alpha1.OpenTelemetryCollector, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(opentelemetrycollectorsResource, c.ns, openTelemetryCollector), &v1alpha1.OpenTelemetryCollector{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.OpenTelemetryCollector), err -} - -// Update takes the representation of a openTelemetryCollector and updates it. Returns the server's representation of the openTelemetryCollector, and an error, if there is any. -func (c *FakeOpenTelemetryCollectors) Update(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.UpdateOptions) (result *v1alpha1.OpenTelemetryCollector, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(opentelemetrycollectorsResource, c.ns, openTelemetryCollector), &v1alpha1.OpenTelemetryCollector{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.OpenTelemetryCollector), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeOpenTelemetryCollectors) UpdateStatus(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.UpdateOptions) (*v1alpha1.OpenTelemetryCollector, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(opentelemetrycollectorsResource, "status", c.ns, openTelemetryCollector), &v1alpha1.OpenTelemetryCollector{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.OpenTelemetryCollector), err -} - -// Delete takes name of the openTelemetryCollector and deletes it. Returns an error if one occurs. -func (c *FakeOpenTelemetryCollectors) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(opentelemetrycollectorsResource, c.ns, name), &v1alpha1.OpenTelemetryCollector{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeOpenTelemetryCollectors) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(opentelemetrycollectorsResource, c.ns, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.OpenTelemetryCollectorList{}) - return err -} - -// Patch applies the patch and returns the patched openTelemetryCollector. -func (c *FakeOpenTelemetryCollectors) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OpenTelemetryCollector, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(opentelemetrycollectorsResource, c.ns, name, pt, data, subresources...), &v1alpha1.OpenTelemetryCollector{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.OpenTelemetryCollector), err -} diff --git a/pkg/client/versioned/typed/opentelemetry/v1alpha1/generated_expansion.go b/pkg/client/versioned/typed/opentelemetry/v1alpha1/generated_expansion.go deleted file mode 100644 index 4793de80ff..0000000000 --- a/pkg/client/versioned/typed/opentelemetry/v1alpha1/generated_expansion.go +++ /dev/null @@ -1,5 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -type OpenTelemetryCollectorExpansion interface{} diff --git a/pkg/client/versioned/typed/opentelemetry/v1alpha1/opentelemetry_client.go b/pkg/client/versioned/typed/opentelemetry/v1alpha1/opentelemetry_client.go deleted file mode 100644 index 7b367e52fa..0000000000 --- a/pkg/client/versioned/typed/opentelemetry/v1alpha1/opentelemetry_client.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - rest "k8s.io/client-go/rest" - - v1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/scheme" -) - -type OpentelemetryV1alpha1Interface interface { - RESTClient() rest.Interface - OpenTelemetryCollectorsGetter -} - -// OpentelemetryV1alpha1Client is used to interact with features provided by the opentelemetry.io group. -type OpentelemetryV1alpha1Client struct { - restClient rest.Interface -} - -func (c *OpentelemetryV1alpha1Client) OpenTelemetryCollectors(namespace string) OpenTelemetryCollectorInterface { - return newOpenTelemetryCollectors(c, namespace) -} - -// NewForConfig creates a new OpentelemetryV1alpha1Client for the given config. -func NewForConfig(c *rest.Config) (*OpentelemetryV1alpha1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &OpentelemetryV1alpha1Client{client}, nil -} - -// NewForConfigOrDie creates a new OpentelemetryV1alpha1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *OpentelemetryV1alpha1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new OpentelemetryV1alpha1Client for the given RESTClient. -func New(c rest.Interface) *OpentelemetryV1alpha1Client { - return &OpentelemetryV1alpha1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1alpha1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *OpentelemetryV1alpha1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/pkg/client/versioned/typed/opentelemetry/v1alpha1/opentelemetrycollector.go b/pkg/client/versioned/typed/opentelemetry/v1alpha1/opentelemetrycollector.go deleted file mode 100644 index d00642555f..0000000000 --- a/pkg/client/versioned/typed/opentelemetry/v1alpha1/opentelemetrycollector.go +++ /dev/null @@ -1,180 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "context" - "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" - - v1alpha1 "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - scheme "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/scheme" -) - -// OpenTelemetryCollectorsGetter has a method to return a OpenTelemetryCollectorInterface. -// A group's client should implement this interface. -type OpenTelemetryCollectorsGetter interface { - OpenTelemetryCollectors(namespace string) OpenTelemetryCollectorInterface -} - -// OpenTelemetryCollectorInterface has methods to work with OpenTelemetryCollector resources. -type OpenTelemetryCollectorInterface interface { - Create(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.CreateOptions) (*v1alpha1.OpenTelemetryCollector, error) - Update(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.UpdateOptions) (*v1alpha1.OpenTelemetryCollector, error) - UpdateStatus(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.UpdateOptions) (*v1alpha1.OpenTelemetryCollector, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.OpenTelemetryCollector, error) - List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.OpenTelemetryCollectorList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OpenTelemetryCollector, err error) - OpenTelemetryCollectorExpansion -} - -// openTelemetryCollectors implements OpenTelemetryCollectorInterface -type openTelemetryCollectors struct { - client rest.Interface - ns string -} - -// newOpenTelemetryCollectors returns a OpenTelemetryCollectors -func newOpenTelemetryCollectors(c *OpentelemetryV1alpha1Client, namespace string) *openTelemetryCollectors { - return &openTelemetryCollectors{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the openTelemetryCollector, and returns the corresponding openTelemetryCollector object, and an error if there is any. -func (c *openTelemetryCollectors) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OpenTelemetryCollector, err error) { - result = &v1alpha1.OpenTelemetryCollector{} - err = c.client.Get(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(ctx). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of OpenTelemetryCollectors that match those selectors. -func (c *openTelemetryCollectors) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OpenTelemetryCollectorList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.OpenTelemetryCollectorList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Do(ctx). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested openTelemetryCollectors. -func (c *openTelemetryCollectors) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - VersionedParams(&opts, scheme.ParameterCodec). - Timeout(timeout). - Watch(ctx) -} - -// Create takes the representation of a openTelemetryCollector and creates it. Returns the server's representation of the openTelemetryCollector, and an error, if there is any. -func (c *openTelemetryCollectors) Create(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.CreateOptions) (result *v1alpha1.OpenTelemetryCollector, err error) { - result = &v1alpha1.OpenTelemetryCollector{} - err = c.client.Post(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(openTelemetryCollector). - Do(ctx). - Into(result) - return -} - -// Update takes the representation of a openTelemetryCollector and updates it. Returns the server's representation of the openTelemetryCollector, and an error, if there is any. -func (c *openTelemetryCollectors) Update(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.UpdateOptions) (result *v1alpha1.OpenTelemetryCollector, err error) { - result = &v1alpha1.OpenTelemetryCollector{} - err = c.client.Put(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - Name(openTelemetryCollector.Name). - VersionedParams(&opts, scheme.ParameterCodec). - Body(openTelemetryCollector). - Do(ctx). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *openTelemetryCollectors) UpdateStatus(ctx context.Context, openTelemetryCollector *v1alpha1.OpenTelemetryCollector, opts v1.UpdateOptions) (result *v1alpha1.OpenTelemetryCollector, err error) { - result = &v1alpha1.OpenTelemetryCollector{} - err = c.client.Put(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - Name(openTelemetryCollector.Name). - SubResource("status"). - VersionedParams(&opts, scheme.ParameterCodec). - Body(openTelemetryCollector). - Do(ctx). - Into(result) - return -} - -// Delete takes name of the openTelemetryCollector and deletes it. Returns an error if one occurs. -func (c *openTelemetryCollectors) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *openTelemetryCollectors) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.client.Delete(). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - VersionedParams(&listOpts, scheme.ParameterCodec). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -// Patch applies the patch and returns the patched openTelemetryCollector. -func (c *openTelemetryCollectors) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OpenTelemetryCollector, err error) { - result = &v1alpha1.OpenTelemetryCollector{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("opentelemetrycollectors"). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, scheme.ParameterCodec). - Body(data). - Do(ctx). - Into(result) - return -} diff --git a/pkg/collector/adapters/adapters_suite_test.go b/pkg/collector/adapters/adapters_suite_test.go new file mode 100644 index 0000000000..75c8c3c76b --- /dev/null +++ b/pkg/collector/adapters/adapters_suite_test.go @@ -0,0 +1,13 @@ +package adapters_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestAdapters(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Adapters Suite") +} diff --git a/pkg/collector/adapters/config_from.go b/pkg/collector/adapters/config_from.go new file mode 100644 index 0000000000..5f3466907b --- /dev/null +++ b/pkg/collector/adapters/config_from.go @@ -0,0 +1,23 @@ +package adapters + +import ( + "errors" + + "gopkg.in/yaml.v2" +) + +var ( + // ErrInvalidYAML represents an error in the format of the configuration file + ErrInvalidYAML = errors.New("couldn't parse the opentelemetry-collector configuration to assemble a list of ports for the service") +) + +// ConfigFromString extracts a configuration map from the given string. +// If the given string isn't a valid YAML, ErrInvalidYAML is returned. +func ConfigFromString(configStr string) (map[interface{}]interface{}, error) { + config := make(map[interface{}]interface{}) + if err := yaml.Unmarshal([]byte(configStr), &config); err != nil { + return nil, ErrInvalidYAML + } + + return config, nil +} diff --git a/pkg/collector/adapters/config_from_test.go b/pkg/collector/adapters/config_from_test.go new file mode 100644 index 0000000000..b87fea6fa9 --- /dev/null +++ b/pkg/collector/adapters/config_from_test.go @@ -0,0 +1,28 @@ +package adapters_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/adapters" +) + +var _ = Describe("ConfigFromString", func() { + Describe("Invalid YAML", func() { + It("should return an error", func() { + // test + config, err := adapters.ConfigFromString("🦄") + + // verify + Expect(config).To(BeNil()) + Expect(err).To(MatchError(adapters.ErrInvalidYAML)) + }) + }) + + Describe("Empty string", func() { + It("should return an empty config", func() { + // test and verify + Expect(adapters.ConfigFromString("")).To(BeEmpty()) + }) + }) +}) diff --git a/pkg/adapters/config_to_ports.go b/pkg/collector/adapters/config_to_ports.go similarity index 84% rename from pkg/adapters/config_to_ports.go rename to pkg/collector/adapters/config_to_ports.go index ba7f760026..b219b20510 100644 --- a/pkg/adapters/config_to_ports.go +++ b/pkg/collector/adapters/config_to_ports.go @@ -1,14 +1,12 @@ package adapters import ( - "context" "errors" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/parser" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/parser" ) var ( @@ -20,9 +18,7 @@ var ( ) // ConfigToReceiverPorts converts the incoming configuration object into a set of service ports required by the receivers. -func ConfigToReceiverPorts(ctx context.Context, config map[interface{}]interface{}) ([]corev1.ServicePort, error) { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - +func ConfigToReceiverPorts(logger logr.Logger, config map[interface{}]interface{}) ([]corev1.ServicePort, error) { // now, we gather which ports we might need to open // for that, we get all the receivers and check their `endpoint` properties, // extracting the port from it. The port name has to be a "DNS_LABEL", so, we try to make it follow the pattern: @@ -56,9 +52,9 @@ func ConfigToReceiverPorts(ctx context.Context, config map[interface{}]interface } rcvrName := key.(string) - rcvrParser := parser.For(rcvrName, receiver) + rcvrParser := parser.For(logger, rcvrName, receiver) - rcvrPorts, err := rcvrParser.Ports(ctx) + rcvrPorts, err := rcvrParser.Ports() if err != nil { // should we break the process and return an error, or just ignore this faulty parser // and let the other parsers add their ports to the service? right now, the best diff --git a/pkg/collector/adapters/config_to_ports_test.go b/pkg/collector/adapters/config_to_ports_test.go new file mode 100644 index 0000000000..afb0ca68fa --- /dev/null +++ b/pkg/collector/adapters/config_to_ports_test.go @@ -0,0 +1,169 @@ +package adapters_test + +import ( + "errors" + + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/adapters" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/parser" +) + +var _ = Describe("ConfigToReceiverPorts", func() { + logger := logf.Log.WithName("unit-tests") + + Describe("Extract ports from config", func() { + It("extract all known ports", func() { + configStr := `receivers: + examplereceiver: + endpoint: "0.0.0.0:12345" + examplereceiver/settings: + endpoint: "0.0.0.0:12346" + examplereceiver/invalid-ignored: + endpoint: "0.0.0.0" + examplereceiver/invalid-not-number: + endpoint: "0.0.0.0:not-number" + examplereceiver/without-endpoint: + notendpoint: "0.0.0.0:12347" + jaeger: + protocols: + grpc: + thrift_compact: + thrift_binary: + endpoint: 0.0.0.0:6833 + jaeger/custom: + protocols: + thrift_http: + endpoint: 0.0.0.0:15268 +` + + // prepare + config, err := adapters.ConfigFromString(configStr) + Expect(config).ToNot(BeEmpty()) + Expect(err).ToNot(HaveOccurred()) + + // test + ports, err := adapters.ConfigToReceiverPorts(logger, config) + Expect(ports).To(HaveLen(6)) + Expect(err).ToNot(HaveOccurred()) + + // verify + expectedPorts := map[int32]bool{} + expectedPorts[int32(12345)] = false + expectedPorts[int32(12346)] = false + expectedPorts[int32(14250)] = false + expectedPorts[int32(6831)] = false + expectedPorts[int32(6833)] = false + expectedPorts[int32(15268)] = false + + expectedNames := map[string]bool{} + expectedNames["examplereceiver"] = false + expectedNames["examplereceiver-settings"] = false + expectedNames["jaeger-grpc"] = false + expectedNames["jaeger-thrift-compact"] = false + expectedNames["jaeger-thrift-binary"] = false + expectedNames["jaeger-custom-thrift-http"] = false + + // make sure we only have the ports in the set + for _, port := range ports { + Expect(expectedPorts).To(HaveKey(port.Port)) + Expect(expectedNames).To(HaveKey(port.Name)) + expectedPorts[port.Port] = true + expectedNames[port.Name] = true + } + + // and make sure all the ports from the set are there + for _, val := range expectedPorts { + Expect(val).To(BeTrue()) + } + + }) + }) + + DescribeTable("No ports are parsed", + func(configStr string, expected error) { + // prepare + config, err := adapters.ConfigFromString(configStr) + Expect(err).ToNot(HaveOccurred()) + + // test + ports, err := adapters.ConfigToReceiverPorts(logger, config) + + // verify + Expect(ports).To(BeNil()) + Expect(err).To(MatchError(expected)) + }, + Entry("empty", "", adapters.ErrNoReceivers), + Entry("not a map", "receivers: some-string", adapters.ErrReceiversNotAMap), + ) + + DescribeTable("Invalid receivers", + func(configStr string) { + // prepare + config, err := adapters.ConfigFromString(configStr) + Expect(err).ToNot(HaveOccurred()) + + // test + ports, err := adapters.ConfigToReceiverPorts(logger, config) + + // verify + Expect(ports).To(HaveLen(0)) + Expect(err).ToNot(HaveOccurred()) + }, + Entry("receiver isn't a map", "receivers:\n some-receiver: string"), + Entry("receiver's endpoint isn't string", "receivers:\n some-receiver:\n endpoint: 123"), + ) + + Describe("Parser failed", func() { + It("should return an empty list of ports", func() { + // prepare + mockParserCalled := false + mockParser := &mockParser{ + portsFunc: func() ([]v1.ServicePort, error) { + mockParserCalled = true + return nil, errors.New("mocked error") + }, + } + parser.Register("mock", func(logger logr.Logger, name string, config map[interface{}]interface{}) parser.ReceiverParser { + return mockParser + }) + + config := map[interface{}]interface{}{ + "receivers": map[interface{}]interface{}{ + "mock": map[interface{}]interface{}{}, + }, + } + + // test + ports, err := adapters.ConfigToReceiverPorts(logger, config) + + // verify + Expect(ports).To(HaveLen(0)) + Expect(err).ToNot(HaveOccurred()) + Expect(mockParserCalled).To(BeTrue()) + }) + }) + +}) + +type mockParser struct { + portsFunc func() ([]corev1.ServicePort, error) +} + +func (m *mockParser) Ports() ([]corev1.ServicePort, error) { + if m.portsFunc != nil { + return m.portsFunc() + } + + return nil, nil +} + +func (m *mockParser) ParserName() string { + return "__mock-adapters" +} diff --git a/pkg/collector/labels.go b/pkg/collector/labels.go new file mode 100644 index 0000000000..c0deb165d2 --- /dev/null +++ b/pkg/collector/labels.go @@ -0,0 +1,39 @@ +// Copyright The OpenTelemetry Authors +// +// 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 collector + +import ( + "fmt" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" +) + +// Labels return the common labels to all objects that are part of a managed OpenTelemetryCollector +func Labels(instance v1alpha1.OpenTelemetryCollector) map[string]string { + // new map every time, so that we don't touch the instance's label + base := map[string]string{} + if nil != instance.Labels { + for k, v := range instance.Labels { + base[k] = v + } + } + + base["app.kubernetes.io/managed-by"] = "opentelemetry-operator" + base["app.kubernetes.io/instance"] = fmt.Sprintf("%s.%s", instance.Namespace, instance.Name) + base["app.kubernetes.io/part-of"] = "opentelemetry" + base["app.kubernetes.io/component"] = "opentelemetry-collector" + + return base +} diff --git a/pkg/collector/parser/parser_suite_test.go b/pkg/collector/parser/parser_suite_test.go new file mode 100644 index 0000000000..8c5384c3d3 --- /dev/null +++ b/pkg/collector/parser/parser_suite_test.go @@ -0,0 +1,13 @@ +package parser_test + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestParser(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Parser Suite") +} diff --git a/pkg/parser/receiver.go b/pkg/collector/parser/receiver.go similarity index 83% rename from pkg/parser/receiver.go rename to pkg/collector/parser/receiver.go index 7d6a3fcec5..466e1f6bc4 100644 --- a/pkg/parser/receiver.go +++ b/pkg/collector/parser/receiver.go @@ -1,7 +1,6 @@ package parser import ( - "context" "fmt" "regexp" "strconv" @@ -10,8 +9,6 @@ import ( "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" ) var ( @@ -22,14 +19,14 @@ var ( // ReceiverParser is an interface that should be implemented by all receiver parsers type ReceiverParser interface { // Ports returns the service ports parsed based on the receiver's configuration - Ports(context.Context) ([]corev1.ServicePort, error) + Ports() ([]corev1.ServicePort, error) // ParserName returns the name of this parser ParserName() string } // Builder specifies the signature required for parser builders -type Builder func(name string, config map[interface{}]interface{}) ReceiverParser +type Builder func(logr.Logger, string, map[interface{}]interface{}) ReceiverParser // registry holds a record of all known parsers var registry = make(map[string]Builder) @@ -45,9 +42,9 @@ func BuilderFor(name string) Builder { } // For returns a new parser for the given receiver name + config -func For(name string, config map[interface{}]interface{}) ReceiverParser { +func For(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { builder := BuilderFor(name) - return builder(name, config) + return builder(logger, name, config) } // Register adds a new parser builder to the list of known builders @@ -55,8 +52,13 @@ func Register(name string, builder Builder) { registry[name] = builder } -func singlePortFromConfigEndpoint(ctx context.Context, name string, config map[interface{}]interface{}) *v1.ServicePort { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) +// IsRegistered checks whether a parser is registered with the given name +func IsRegistered(name string) bool { + _, ok := registry[name] + return ok +} + +func singlePortFromConfigEndpoint(logger logr.Logger, name string, config map[interface{}]interface{}) *v1.ServicePort { endpoint, ok := config["endpoint"] if !ok { logger.V(2).Info("receiver doesn't have an endpoint") diff --git a/pkg/parser/receiver_carbon.go b/pkg/collector/parser/receiver_carbon.go similarity index 66% rename from pkg/parser/receiver_carbon.go rename to pkg/collector/parser/receiver_carbon.go index 8c0da5de76..29b0daf340 100644 --- a/pkg/parser/receiver_carbon.go +++ b/pkg/collector/parser/receiver_carbon.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameCarbon = "__carbon" // NewCarbonReceiverParser builds a new parser for Carbon receivers, from the contrib repository -func NewCarbonReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewCarbonReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 2003, diff --git a/pkg/parser/receiver_carbon_test.go b/pkg/collector/parser/receiver_carbon_test.go similarity index 100% rename from pkg/parser/receiver_carbon_test.go rename to pkg/collector/parser/receiver_carbon_test.go diff --git a/pkg/parser/receiver_collectd.go b/pkg/collector/parser/receiver_collectd.go similarity index 67% rename from pkg/parser/receiver_collectd.go rename to pkg/collector/parser/receiver_collectd.go index 4591e3b19c..fa275633a0 100644 --- a/pkg/parser/receiver_collectd.go +++ b/pkg/collector/parser/receiver_collectd.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameCollectd = "__collectd" // NewCollectdReceiverParser builds a new parser for Collectd receivers, from the contrib repository -func NewCollectdReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewCollectdReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 8081, diff --git a/pkg/parser/receiver_collectd_test.go b/pkg/collector/parser/receiver_collectd_test.go similarity index 100% rename from pkg/parser/receiver_collectd_test.go rename to pkg/collector/parser/receiver_collectd_test.go diff --git a/pkg/parser/receiver_generic.go b/pkg/collector/parser/receiver_generic.go similarity index 75% rename from pkg/parser/receiver_generic.go rename to pkg/collector/parser/receiver_generic.go index caf03d898f..a62d719bf0 100644 --- a/pkg/parser/receiver_generic.go +++ b/pkg/collector/parser/receiver_generic.go @@ -1,8 +1,7 @@ package parser import ( - "context" - + "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" ) @@ -12,6 +11,7 @@ var _ ReceiverParser = &GenericReceiver{} // GenericReceiver is a special parser for generic receivers. It doesn't self-register and should be created/used directly type GenericReceiver struct { + logger logr.Logger name string config map[interface{}]interface{} defaultPort int32 @@ -19,8 +19,9 @@ type GenericReceiver struct { } // NewGenericReceiverParser builds a new parser for generic receivers -func NewGenericReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewGenericReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, parserName: parserNameGeneric, @@ -28,8 +29,8 @@ func NewGenericReceiverParser(name string, config map[interface{}]interface{}) R } // Ports returns all the service ports for all protocols in this parser -func (g *GenericReceiver) Ports(ctx context.Context) ([]corev1.ServicePort, error) { - port := singlePortFromConfigEndpoint(ctx, g.name, g.config) +func (g *GenericReceiver) Ports() ([]corev1.ServicePort, error) { + port := singlePortFromConfigEndpoint(g.logger, g.name, g.config) if port != nil { return []corev1.ServicePort{*port}, nil } diff --git a/pkg/collector/parser/receiver_generic_test.go b/pkg/collector/parser/receiver_generic_test.go new file mode 100644 index 0000000000..f4e8907dcd --- /dev/null +++ b/pkg/collector/parser/receiver_generic_test.go @@ -0,0 +1,100 @@ +package parser_test + +import ( + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/parser" +) + +var _ = Describe("Generic receivers", func() { + logger := logf.Log.WithName("unit-tests") + + It("should parse the endpoint", func() { + // prepare + // there's no parser registered to handle "myreceiver", so, it falls back to the generic parser + builder := parser.NewGenericReceiverParser(logger, "myreceiver", map[interface{}]interface{}{ + "endpoint": "0.0.0.0:1234", + }) + + // test + ports, err := builder.Ports() + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(ports).To(HaveLen(1)) + Expect(ports[0].Port).To(BeEquivalentTo(1234)) + }) + + It("should have failed to parse the endpoint", func() { + // prepare + // there's no parser registered to handle "myreceiver", so, it falls back to the generic parser + builder := parser.NewGenericReceiverParser(logger, "myreceiver", map[interface{}]interface{}{ + "endpoint": "0.0.0.0", + }) + + // test + ports, err := builder.Ports() + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(ports).To(HaveLen(0)) + }) + + DescribeTable("downstream parsers", + func(receiverName, parserName string, defaultPort int, builder func(logr.Logger, string, map[interface{}]interface{}) parser.ReceiverParser) { + Describe("builds successfully", func() { + // test + builder := builder(logger, receiverName, map[interface{}]interface{}{}) + + // verify + Expect(builder.ParserName()).To(Equal(parserName)) + }) + + Describe("assigns the expected port", func() { + // prepare + builder := builder(logger, receiverName, map[interface{}]interface{}{}) + + // test + ports, err := builder.Ports() + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(ports).To(HaveLen(1)) + Expect(ports[0].Port).To(BeEquivalentTo(defaultPort)) + Expect(ports[0].Name).To(Equal(receiverName)) + }) + + Describe("allows port to be overridden", func() { + // prepare + builder := builder(logger, receiverName, map[interface{}]interface{}{ + "endpoint": "0.0.0.0:65535", + }) + + // test + ports, err := builder.Ports() + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(ports).To(HaveLen(1)) + Expect(ports[0].Port).To(BeEquivalentTo(65535)) + Expect(ports[0].Name).To(Equal(receiverName)) + }) + }, + Entry("zipkin", "zipkin", "__zipkin", 9411, parser.NewZipkinReceiverParser), + Entry("opencensus", "opencensus", "__opencensus", 55678, parser.NewOpenCensusReceiverParser), + Entry("otlp", "otlp", "__otlp", 55680, parser.NewOTLPReceiverParser), + + // contrib receivers + Entry("carbon", "carbon", "__carbon", 2003, parser.NewCarbonReceiverParser), + Entry("collectd", "collectd", "__collectd", 8081, parser.NewCollectdReceiverParser), + Entry("sapm", "sapm", "__sapm", 7276, parser.NewSAPMReceiverParser), + Entry("signalfx", "signalfx", "__signalfx", 9943, parser.NewSignalFxReceiverParser), + Entry("wavefront", "wavefront", "__wavefront", 2003, parser.NewWavefrontReceiverParser), + Entry("zipkin-scribe", "zipkin-scribe", "__zipkinscribe", 9410, parser.NewZipkinScribeReceiverParser), + ) + +}) diff --git a/pkg/parser/receiver_jaeger.go b/pkg/collector/parser/receiver_jaeger.go similarity index 87% rename from pkg/parser/receiver_jaeger.go rename to pkg/collector/parser/receiver_jaeger.go index 39b168e2d2..ec3ff16a4a 100644 --- a/pkg/parser/receiver_jaeger.go +++ b/pkg/collector/parser/receiver_jaeger.go @@ -1,9 +1,9 @@ package parser import ( - "context" "fmt" + "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" ) @@ -20,14 +20,16 @@ const ( // JaegerReceiverParser parses the configuration for Jaeger-specific receivers type JaegerReceiverParser struct { + logger logr.Logger name string config map[interface{}]interface{} } // NewJaegerReceiverParser builds a new parser for Jaeger receivers -func NewJaegerReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewJaegerReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { if protocols, ok := config["protocols"].(map[interface{}]interface{}); ok { return &JaegerReceiverParser{ + logger: logger, name: name, config: protocols, } @@ -40,7 +42,7 @@ func NewJaegerReceiverParser(name string, config map[interface{}]interface{}) Re } // Ports returns all the service ports for all protocols in this parser -func (j *JaegerReceiverParser) Ports(ctx context.Context) ([]corev1.ServicePort, error) { +func (j *JaegerReceiverParser) Ports() ([]corev1.ServicePort, error) { ports := []corev1.ServicePort{} for _, protocol := range []struct { @@ -73,7 +75,7 @@ func (j *JaegerReceiverParser) Ports(ctx context.Context) ([]corev1.ServicePort, // do we have a configuration block for the protocol? settings, ok := receiverProtocol.(map[interface{}]interface{}) if ok { - protocolPort = singlePortFromConfigEndpoint(ctx, nameWithProtocol, settings) + protocolPort = singlePortFromConfigEndpoint(j.logger, nameWithProtocol, settings) } // have we parsed a port based on the configuration block? diff --git a/pkg/collector/parser/receiver_jaeger_test.go b/pkg/collector/parser/receiver_jaeger_test.go new file mode 100644 index 0000000000..8637713552 --- /dev/null +++ b/pkg/collector/parser/receiver_jaeger_test.go @@ -0,0 +1,101 @@ +package parser_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/parser" +) + +var _ = Describe("Jaeger receiver", func() { + logger := logf.Log.WithName("unit-tests") + + It("should have self registered", func() { + // verify + Expect(parser.IsRegistered("jaeger")).To(BeTrue()) + }) + + It("should be found via its parser name", func() { + // test + p := parser.For(logger, "jaeger", map[interface{}]interface{}{}) + + // verify + Expect(p.ParserName()).To(Equal("__jaeger")) + }) + + It("should build with a minimal configuration", func() { + // prepare + builder := parser.NewJaegerReceiverParser(logger, "jaeger", map[interface{}]interface{}{ + "protocols": map[interface{}]interface{}{ + "grpc": map[interface{}]interface{}{}, + }, + }) + + // test + ports, err := builder.Ports() + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(ports).To(HaveLen(1)) + Expect(ports[0].Port).To(BeEquivalentTo(14250)) + }) + + It("should allow ports to be overridden", func() { + // prepare + builder := parser.NewJaegerReceiverParser(logger, "jaeger", map[interface{}]interface{}{ + "protocols": map[interface{}]interface{}{ + "grpc": map[interface{}]interface{}{ + "endpoint": "0.0.0.0:1234", + }, + }, + }) + + // test + ports, err := builder.Ports() + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(ports).To(HaveLen(1)) + Expect(ports[0].Port).To(BeEquivalentTo(1234)) + }) + + It("should expose the default ports", func() { + // prepare + builder := parser.NewJaegerReceiverParser(logger, "jaeger", map[interface{}]interface{}{ + "protocols": map[interface{}]interface{}{ + "grpc": map[interface{}]interface{}{}, + "thrift_http": map[interface{}]interface{}{}, + "thrift_compact": map[interface{}]interface{}{}, + "thrift_binary": map[interface{}]interface{}{}, + }, + }) + + expectedResults := map[string]struct { + portNumber int32 + seen bool + }{ + "jaeger-grpc": {portNumber: 14250}, + "jaeger-thrift-http": {portNumber: 14268}, + "jaeger-thrift-compact": {portNumber: 6831}, + "jaeger-thrift-binary": {portNumber: 6832}, + } + + // test + ports, err := builder.Ports() + + // verify + Expect(err).ToNot(HaveOccurred()) + Expect(ports).To(HaveLen(4)) + + for _, port := range ports { + r := expectedResults[port.Name] + r.seen = true + expectedResults[port.Name] = r + Expect(port.Port).To(BeEquivalentTo(r.portNumber)) + } + for k, v := range expectedResults { + Expect(v.seen).To(BeTrue(), "the port %s wasn't included in the service ports", k) + } + }) +}) diff --git a/pkg/parser/receiver_oc.go b/pkg/collector/parser/receiver_oc.go similarity index 65% rename from pkg/parser/receiver_oc.go rename to pkg/collector/parser/receiver_oc.go index c7fbcbdf8a..ee188dd82a 100644 --- a/pkg/parser/receiver_oc.go +++ b/pkg/collector/parser/receiver_oc.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameOpenCensus = "__opencensus" // NewOpenCensusReceiverParser builds a new parser for OpenCensus receivers -func NewOpenCensusReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewOpenCensusReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 55678, diff --git a/pkg/parser/receiver_oc_test.go b/pkg/collector/parser/receiver_oc_test.go similarity index 100% rename from pkg/parser/receiver_oc_test.go rename to pkg/collector/parser/receiver_oc_test.go diff --git a/pkg/parser/receiver_otlp.go b/pkg/collector/parser/receiver_otlp.go similarity index 63% rename from pkg/parser/receiver_otlp.go rename to pkg/collector/parser/receiver_otlp.go index e6396d4053..acf19b6fa1 100644 --- a/pkg/parser/receiver_otlp.go +++ b/pkg/collector/parser/receiver_otlp.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameOTLP = "__otlp" // NewOTLPReceiverParser builds a new parser for OTLP receivers -func NewOTLPReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewOTLPReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 55680, diff --git a/pkg/parser/receiver_otlp_test.go b/pkg/collector/parser/receiver_otlp_test.go similarity index 100% rename from pkg/parser/receiver_otlp_test.go rename to pkg/collector/parser/receiver_otlp_test.go diff --git a/pkg/parser/receiver_sapm.go b/pkg/collector/parser/receiver_sapm.go similarity index 65% rename from pkg/parser/receiver_sapm.go rename to pkg/collector/parser/receiver_sapm.go index fcb911ab50..ba1cef23f2 100644 --- a/pkg/parser/receiver_sapm.go +++ b/pkg/collector/parser/receiver_sapm.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameSAPM = "__sapm" // NewSAPMReceiverParser builds a new parser for SAPM receivers, from the contrib repository -func NewSAPMReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewSAPMReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 7276, diff --git a/pkg/parser/receiver_sapm_test.go b/pkg/collector/parser/receiver_sapm_test.go similarity index 100% rename from pkg/parser/receiver_sapm_test.go rename to pkg/collector/parser/receiver_sapm_test.go diff --git a/pkg/parser/receiver_signalfx.go b/pkg/collector/parser/receiver_signalfx.go similarity index 67% rename from pkg/parser/receiver_signalfx.go rename to pkg/collector/parser/receiver_signalfx.go index f4f5ec758e..9676aa871f 100644 --- a/pkg/parser/receiver_signalfx.go +++ b/pkg/collector/parser/receiver_signalfx.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameSignalFx = "__signalfx" // NewSignalFxReceiverParser builds a new parser for SignalFx receivers, from the contrib repository -func NewSignalFxReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewSignalFxReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 9943, diff --git a/pkg/parser/receiver_signalfx_test.go b/pkg/collector/parser/receiver_signalfx_test.go similarity index 100% rename from pkg/parser/receiver_signalfx_test.go rename to pkg/collector/parser/receiver_signalfx_test.go diff --git a/pkg/collector/parser/receiver_test.go b/pkg/collector/parser/receiver_test.go new file mode 100644 index 0000000000..e44b0aa461 --- /dev/null +++ b/pkg/collector/parser/receiver_test.go @@ -0,0 +1,100 @@ +package parser + +import ( + "github.com/go-logr/logr" + . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/extensions/table" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" +) + +var _ = Describe("Receiver", func() { + logger := logf.Log.WithName("unit-tests") + + DescribeTable("port names", + func(candidate string, port int, expected string) { + // test and verify + Expect(portName(candidate, int32(port))).To(Equal(expected)) + }, + Entry("regular case", "my-receiver", 123, "my-receiver"), + Entry("name too long", "long-name-long-name-long-name-long-name-long-name-long-name-long-name-long-name", 123, "port-123"), + Entry("name with invalid chars", "my-🦄-receiver", 123, "port-123"), + Entry("name starting with invalid char", "-my-receiver", 123, "port-123"), + ) + + DescribeTable("receiver type", + func(name string, expected string) { + // test and verify + Expect(receiverType(name)).To(Equal(expected)) + }, + Entry("regular case", "myreceiver", "myreceiver"), + Entry("named instance", "myreceiver/custom", "myreceiver"), + ) + + DescribeTable("parse port from endpoint", + func(endpoint string, expected int, errorExpected bool) { + // test + val, err := portFromEndpoint(endpoint) + if errorExpected { + Expect(err).To(HaveOccurred()) + } else { + Expect(err).ToNot(HaveOccurred()) + } + + Expect(val).To(BeEquivalentTo(expected), "wrong port from endpoint %s: %d", endpoint, val) + }, + Entry("regular case", "http://localhost:1234", 1234, false), + Entry("no protocol", "0.0.0.0:1234", 1234, false), + Entry("just port", ":1234", 1234, false), + Entry("no port at all", "http://localhost", 0, true), + ) + + It("should fail when the port isn't a string", func() { + // prepare + config := map[interface{}]interface{}{ + "endpoint": 123, + } + + // test + p := singlePortFromConfigEndpoint(logger, "myreceiver", config) + + // verify + Expect(p).To(BeNil()) + }) + + It("should fallback to generic parser when receiver isn't registered", func() { + // test + p := For(logger, "myreceiver", map[interface{}]interface{}{}) + + // test + Expect(p.ParserName()).To(Equal("__generic")) + }) + + It("should find a registered parser", func() { + // prepare + builderCalled := false + Register("mock", func(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { + builderCalled = true + return &mockParser{} + }) + + // test + For(logger, "mock", map[interface{}]interface{}{}) + + // verify + Expect(builderCalled).To(BeTrue()) + }) +}) + +type mockParser struct { + portsFunc func() ([]corev1.ServicePort, error) +} + +func (m *mockParser) Ports() ([]corev1.ServicePort, error) { + return nil, nil +} + +func (m *mockParser) ParserName() string { + return "__mock" +} diff --git a/pkg/parser/receiver_wavefront.go b/pkg/collector/parser/receiver_wavefront.go similarity index 67% rename from pkg/parser/receiver_wavefront.go rename to pkg/collector/parser/receiver_wavefront.go index 86358e28d1..1b123dcf96 100644 --- a/pkg/parser/receiver_wavefront.go +++ b/pkg/collector/parser/receiver_wavefront.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameWavefront = "__wavefront" // NewWavefrontReceiverParser builds a new parser for Wavefront receivers, from the contrib repository -func NewWavefrontReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewWavefrontReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 2003, diff --git a/pkg/parser/receiver_wavefront_test.go b/pkg/collector/parser/receiver_wavefront_test.go similarity index 100% rename from pkg/parser/receiver_wavefront_test.go rename to pkg/collector/parser/receiver_wavefront_test.go diff --git a/pkg/parser/receiver_zipkin-scribe.go b/pkg/collector/parser/receiver_zipkin-scribe.go similarity index 66% rename from pkg/parser/receiver_zipkin-scribe.go rename to pkg/collector/parser/receiver_zipkin-scribe.go index b7e0f0fbf9..075e1196b8 100644 --- a/pkg/parser/receiver_zipkin-scribe.go +++ b/pkg/collector/parser/receiver_zipkin-scribe.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameZipkinScribe = "__zipkinscribe" // NewZipkinScribeReceiverParser builds a new parser for ZipkinScribe receivers -func NewZipkinScribeReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewZipkinScribeReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 9410, diff --git a/pkg/parser/receiver_zipkin-scribe_test.go b/pkg/collector/parser/receiver_zipkin-scribe_test.go similarity index 100% rename from pkg/parser/receiver_zipkin-scribe_test.go rename to pkg/collector/parser/receiver_zipkin-scribe_test.go diff --git a/pkg/parser/receiver_zipkin.go b/pkg/collector/parser/receiver_zipkin.go similarity index 64% rename from pkg/parser/receiver_zipkin.go rename to pkg/collector/parser/receiver_zipkin.go index 7c45edb5c7..18e1ac6609 100644 --- a/pkg/parser/receiver_zipkin.go +++ b/pkg/collector/parser/receiver_zipkin.go @@ -1,10 +1,13 @@ package parser +import "github.com/go-logr/logr" + const parserNameZipkin = "__zipkin" // NewZipkinReceiverParser builds a new parser for Zipkin receivers -func NewZipkinReceiverParser(name string, config map[interface{}]interface{}) ReceiverParser { +func NewZipkinReceiverParser(logger logr.Logger, name string, config map[interface{}]interface{}) ReceiverParser { return &GenericReceiver{ + logger: logger, name: name, config: config, defaultPort: 9411, diff --git a/pkg/parser/receiver_zipkin_test.go b/pkg/collector/parser/receiver_zipkin_test.go similarity index 100% rename from pkg/parser/receiver_zipkin_test.go rename to pkg/collector/parser/receiver_zipkin_test.go diff --git a/pkg/collector/reconcile/configmap.go b/pkg/collector/reconcile/configmap.go new file mode 100644 index 0000000000..26236238de --- /dev/null +++ b/pkg/collector/reconcile/configmap.go @@ -0,0 +1,148 @@ +// Copyright The OpenTelemetry Authors +// +// 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 reconcile + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/open-telemetry/opentelemetry-operator/pkg/collector" +) + +// ConfigMaps reconciles the config map(s) required for the instance in the current context +func ConfigMaps(ctx context.Context, params Params) error { + desired := []corev1.ConfigMap{ + desiredConfigMap(ctx, params), + } + + // first, handle the create/update parts + if err := expectedConfigMaps(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the expected deployments: %v", err) + } + + // then, delete the extra objects + if err := deleteConfigMaps(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the deployments to be deleted: %v", err) + } + + return nil +} + +func desiredConfigMap(ctx context.Context, params Params) corev1.ConfigMap { + name := fmt.Sprintf("%s-collector", params.Instance.Name) + + labels := collector.Labels(params.Instance) + labels["app.kubernetes.io/name"] = name + + return corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: params.Instance.Namespace, + Labels: labels, + Annotations: params.Instance.Annotations, + }, + Data: map[string]string{ + "collector.yaml": params.Instance.Spec.Config, + }, + } +} + +func expectedConfigMaps(ctx context.Context, params Params, expected []corev1.ConfigMap) error { + for _, obj := range expected { + desired := obj + + controllerutil.SetControllerReference(¶ms.Instance, &desired, params.Scheme) + + existing := &corev1.ConfigMap{} + nns := types.NamespacedName{Namespace: desired.Namespace, Name: desired.Name} + err := params.Client.Get(ctx, nns, existing) + if err != nil && errors.IsNotFound(err) { + if err := params.Client.Create(ctx, &desired); err != nil { + return fmt.Errorf("failed to create: %w", err) + } + params.Log.V(2).Info("created", "configmap.name", desired.Name, "configmap.namespace", desired.Namespace) + continue + } else if err != nil { + return fmt.Errorf("failed to get: %w", err) + } + + // it exists already, merge the two if the end result isn't identical to the existing one + updated := existing.DeepCopy() + if updated.Annotations == nil { + updated.Annotations = map[string]string{} + } + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + + updated.Data = desired.Data + updated.BinaryData = desired.BinaryData + updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences + + for k, v := range desired.ObjectMeta.Annotations { + updated.ObjectMeta.Annotations[k] = v + } + for k, v := range desired.ObjectMeta.Labels { + updated.ObjectMeta.Labels[k] = v + } + + if err := params.Client.Update(ctx, updated); err != nil { + return fmt.Errorf("failed to apply changes: %w", err) + } + + params.Log.V(2).Info("applied", "configmap.name", desired.Name, "configmap.namespace", desired.Namespace) + } + + return nil +} + +func deleteConfigMaps(ctx context.Context, params Params, expected []corev1.ConfigMap) error { + opts := []client.ListOption{ + client.InNamespace(params.Instance.Namespace), + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.Instance.Namespace, params.Instance.Name), + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }), + } + list := &corev1.ConfigMapList{} + if err := params.Client.List(ctx, list, opts...); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + + for _, existing := range list.Items { + del := true + for _, keep := range expected { + if keep.Name == existing.Name && keep.Namespace == existing.Namespace { + del = false + } + } + + if del { + if err := params.Client.Delete(ctx, &existing); err != nil { + return fmt.Errorf("failed to delete: %w", err) + } + params.Log.V(2).Info("deleted", "configmap.name", existing.Name, "configmap.namespace", existing.Namespace) + } + } + + return nil +} diff --git a/pkg/collector/reconcile/daemonset.go b/pkg/collector/reconcile/daemonset.go new file mode 100644 index 0000000000..ecbef1ce5a --- /dev/null +++ b/pkg/collector/reconcile/daemonset.go @@ -0,0 +1,225 @@ +// Copyright The OpenTelemetry Authors +// +// 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 reconcile + +import ( + "context" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/open-telemetry/opentelemetry-operator/pkg/collector" +) + +// DaemonSets reconciles the daemon set(s) required for the instance in the current context +func DaemonSets(ctx context.Context, params Params) error { + desired := []appsv1.DaemonSet{} + if params.Instance.Spec.Mode == "daemonset" { + desired = append(desired, desiredDaemonSet(ctx, params)) + } + + // first, handle the create/update parts + if err := expectedDaemonSets(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the expected daemon sets: %v", err) + } + + // then, delete the extra objects + if err := deleteDaemonSets(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the daemon sets to be deleted: %v", err) + } + + return nil +} + +func desiredDaemonSet(ctx context.Context, params Params) appsv1.DaemonSet { + name := fmt.Sprintf("%s-collector", params.Instance.Name) + + image := params.Instance.Spec.Image + if len(image) == 0 { + image = params.Config.CollectorImage() + } + + labels := collector.Labels(params.Instance) + labels["app.kubernetes.io/name"] = name + + annotations := params.Instance.Annotations + if annotations == nil { + annotations = map[string]string{} + } + + annotations["prometheus.io/scrape"] = "true" + annotations["prometheus.io/port"] = "8888" + annotations["prometheus.io/path"] = "/metrics" + + argsMap := params.Instance.Spec.Args + if argsMap == nil { + argsMap = map[string]string{} + } + + if _, exists := argsMap["config"]; exists { + params.Log.Info("the 'config' flag isn't allowed and is being ignored") + } + + // this effectively overrides any 'config' entry that might exist in the CR + argsMap["config"] = fmt.Sprintf("/conf/%s", params.Config.CollectorConfigMapEntry()) + + var args []string + for k, v := range argsMap { + args = append(args, fmt.Sprintf("--%s=%s", k, v)) + } + + configMapVolumeName := fmt.Sprintf("otc-internal-%s", name) + volumeMounts := []corev1.VolumeMount{{ + Name: configMapVolumeName, + MountPath: "/conf", + }} + volumes := []corev1.Volume{{ + Name: configMapVolumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{Name: name}, + Items: []corev1.KeyToPath{{ + Key: params.Config.CollectorConfigMapEntry(), + Path: params.Config.CollectorConfigMapEntry(), + }}, + }, + }, + }} + + if len(params.Instance.Spec.VolumeMounts) > 0 { + volumeMounts = append(volumeMounts, params.Instance.Spec.VolumeMounts...) + } + + if len(params.Instance.Spec.Volumes) > 0 { + volumes = append(volumes, params.Instance.Spec.Volumes...) + } + + return appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: params.Instance.Namespace, + Labels: labels, + Annotations: params.Instance.Annotations, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + Annotations: annotations, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: ServiceAccountNameFor(params.Instance), + Containers: []corev1.Container{{ + Name: "opentelemetry-collector", + Image: image, + VolumeMounts: volumeMounts, + Args: args, + }}, + Volumes: volumes, + }, + }, + }, + } + +} + +func expectedDaemonSets(ctx context.Context, params Params, expected []appsv1.DaemonSet) error { + for _, obj := range expected { + desired := obj + + controllerutil.SetControllerReference(¶ms.Instance, &desired, params.Scheme) + + existing := &appsv1.DaemonSet{} + nns := types.NamespacedName{Namespace: desired.Namespace, Name: desired.Name} + err := params.Client.Get(ctx, nns, existing) + if err != nil && k8serrors.IsNotFound(err) { + if err := params.Client.Create(ctx, &desired); err != nil { + return fmt.Errorf("failed to create: %w", err) + } + params.Log.V(2).Info("created", "daemonset.name", desired.Name, "daemonset.namespace", desired.Namespace) + continue + } else if err != nil { + return fmt.Errorf("failed to get: %w", err) + } + + // it exists already, merge the two if the end result isn't identical to the existing one + updated := existing.DeepCopy() + if updated.Annotations == nil { + updated.Annotations = map[string]string{} + } + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + + updated.Spec = desired.Spec + updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences + + for k, v := range desired.ObjectMeta.Annotations { + updated.ObjectMeta.Annotations[k] = v + } + for k, v := range desired.ObjectMeta.Labels { + updated.ObjectMeta.Labels[k] = v + } + + if err := params.Client.Update(ctx, updated); err != nil { + return fmt.Errorf("failed to apply changes: %w", err) + } + + params.Log.V(2).Info("applied", "daemonset.name", desired.Name, "daemonset.namespace", desired.Namespace) + } + + return nil +} + +func deleteDaemonSets(ctx context.Context, params Params, expected []appsv1.DaemonSet) error { + opts := []client.ListOption{ + client.InNamespace(params.Instance.Namespace), + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.Instance.Namespace, params.Instance.Name), + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }), + } + list := &appsv1.DaemonSetList{} + if err := params.Client.List(ctx, list, opts...); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + + for _, existing := range list.Items { + del := true + for _, keep := range expected { + if keep.Name == existing.Name && keep.Namespace == existing.Namespace { + del = false + } + } + + if del { + if err := params.Client.Delete(ctx, &existing); err != nil { + return fmt.Errorf("failed to delete: %w", err) + } + params.Log.V(2).Info("deleted", "daemonset.name", existing.Name, "daemonset.namespace", existing.Namespace) + } + } + + return nil +} diff --git a/pkg/collector/reconcile/deployment.go b/pkg/collector/reconcile/deployment.go new file mode 100644 index 0000000000..0e29ff4067 --- /dev/null +++ b/pkg/collector/reconcile/deployment.go @@ -0,0 +1,225 @@ +// Copyright The OpenTelemetry Authors +// +// 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 reconcile + +import ( + "context" + "fmt" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/open-telemetry/opentelemetry-operator/pkg/collector" +) + +// Deployments reconciles the deployment(s) required for the instance in the current context +func Deployments(ctx context.Context, params Params) error { + desired := []appsv1.Deployment{} + if len(params.Instance.Spec.Mode) == 0 || params.Instance.Spec.Mode == "deployment" { + desired = append(desired, desiredDeployment(ctx, params)) + } + + // first, handle the create/update parts + if err := expectedDeployments(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the expected deployments: %v", err) + } + + // then, delete the extra objects + if err := deleteDeployments(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the deployments to be deleted: %v", err) + } + + return nil +} + +func desiredDeployment(ctx context.Context, params Params) appsv1.Deployment { + name := fmt.Sprintf("%s-collector", params.Instance.Name) + + image := params.Instance.Spec.Image + if len(image) == 0 { + image = params.Config.CollectorImage() + } + + labels := collector.Labels(params.Instance) + labels["app.kubernetes.io/name"] = name + + annotations := params.Instance.Annotations + if annotations == nil { + annotations = map[string]string{} + } + + annotations["prometheus.io/scrape"] = "true" + annotations["prometheus.io/port"] = "8888" + annotations["prometheus.io/path"] = "/metrics" + + argsMap := params.Instance.Spec.Args + if argsMap == nil { + argsMap = map[string]string{} + } + + if _, exists := argsMap["config"]; exists { + params.Log.Info("the 'config' flag isn't allowed and is being ignored") + } + + // this effectively overrides any 'config' entry that might exist in the CR + argsMap["config"] = fmt.Sprintf("/conf/%s", params.Config.CollectorConfigMapEntry()) + + var args []string + for k, v := range argsMap { + args = append(args, fmt.Sprintf("--%s=%s", k, v)) + } + + configMapVolumeName := fmt.Sprintf("otc-internal-%s", name) + volumeMounts := []corev1.VolumeMount{{ + Name: configMapVolumeName, + MountPath: "/conf", + }} + volumes := []corev1.Volume{{ + Name: configMapVolumeName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{Name: name}, + Items: []corev1.KeyToPath{{ + Key: params.Config.CollectorConfigMapEntry(), + Path: params.Config.CollectorConfigMapEntry(), + }}, + }, + }, + }} + + if len(params.Instance.Spec.VolumeMounts) > 0 { + volumeMounts = append(volumeMounts, params.Instance.Spec.VolumeMounts...) + } + + if len(params.Instance.Spec.Volumes) > 0 { + volumes = append(volumes, params.Instance.Spec.Volumes...) + } + + return appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: params.Instance.Namespace, + Labels: labels, + Annotations: params.Instance.Annotations, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: params.Instance.Spec.Replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: labels, + Annotations: annotations, + }, + Spec: corev1.PodSpec{ + ServiceAccountName: ServiceAccountNameFor(params.Instance), + Containers: []corev1.Container{{ + Name: "opentelemetry-collector", + Image: image, + VolumeMounts: volumeMounts, + Args: args, + }}, + Volumes: volumes, + }, + }, + }, + } +} + +func expectedDeployments(ctx context.Context, params Params, expected []appsv1.Deployment) error { + for _, obj := range expected { + desired := obj + + controllerutil.SetControllerReference(¶ms.Instance, &desired, params.Scheme) + + existing := &appsv1.Deployment{} + nns := types.NamespacedName{Namespace: desired.Namespace, Name: desired.Name} + err := params.Client.Get(ctx, nns, existing) + if err != nil && k8serrors.IsNotFound(err) { + if err := params.Client.Create(ctx, &desired); err != nil { + return fmt.Errorf("failed to create: %w", err) + } + params.Log.V(2).Info("created", "deployment.name", desired.Name, "deployment.namespace", desired.Namespace) + continue + } else if err != nil { + return fmt.Errorf("failed to get: %w", err) + } + + // it exists already, merge the two if the end result isn't identical to the existing one + updated := existing.DeepCopy() + if updated.Annotations == nil { + updated.Annotations = map[string]string{} + } + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + + updated.Spec = desired.Spec + updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences + + for k, v := range desired.ObjectMeta.Annotations { + updated.ObjectMeta.Annotations[k] = v + } + for k, v := range desired.ObjectMeta.Labels { + updated.ObjectMeta.Labels[k] = v + } + + if err := params.Client.Update(ctx, updated); err != nil { + return fmt.Errorf("failed to apply changes: %w", err) + } + + params.Log.V(2).Info("applied", "deployment.name", desired.Name, "deployment.namespace", desired.Namespace) + } + + return nil +} + +func deleteDeployments(ctx context.Context, params Params, expected []appsv1.Deployment) error { + opts := []client.ListOption{ + client.InNamespace(params.Instance.Namespace), + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.Instance.Namespace, params.Instance.Name), + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }), + } + list := &appsv1.DeploymentList{} + if err := params.Client.List(ctx, list, opts...); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + + for _, existing := range list.Items { + del := true + for _, keep := range expected { + if keep.Name == existing.Name && keep.Namespace == existing.Namespace { + del = false + } + } + + if del { + if err := params.Client.Delete(ctx, &existing); err != nil { + return fmt.Errorf("failed to delete: %w", err) + } + params.Log.V(2).Info("deleted", "deployment.name", existing.Name, "deployment.namespace", existing.Namespace) + } + } + + return nil +} diff --git a/pkg/collector/reconcile/params.go b/pkg/collector/reconcile/params.go new file mode 100644 index 0000000000..fea53fcc14 --- /dev/null +++ b/pkg/collector/reconcile/params.go @@ -0,0 +1,33 @@ +// Copyright The OpenTelemetry Authors +// +// 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 reconcile + +import ( + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/internal/config" +) + +// Params holds the reconciliation-specific parameters +type Params struct { + Config config.Config + Client client.Client + Instance v1alpha1.OpenTelemetryCollector + Log logr.Logger + Scheme *runtime.Scheme +} diff --git a/pkg/collector/reconcile/service.go b/pkg/collector/reconcile/service.go new file mode 100644 index 0000000000..2c20a8cc9d --- /dev/null +++ b/pkg/collector/reconcile/service.go @@ -0,0 +1,273 @@ +// Copyright The OpenTelemetry Authors +// +// 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 reconcile + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/go-logr/logr" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/adapters" +) + +// Services reconciles the service(s) required for the instance in the current context +func Services(ctx context.Context, params Params) error { + desired := []corev1.Service{} + + type builder func(context.Context, Params) *corev1.Service + for _, builder := range []builder{desiredService, headless, monitoringService} { + svc := builder(ctx, params) + // add only the non-nil to the list + if svc != nil { + desired = append(desired, *svc) + } + } + + // first, handle the create/update parts + if err := expectedServices(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the expected services: %v", err) + } + + // then, delete the extra objects + if err := deleteServices(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the services to be deleted: %v", err) + } + + return nil +} + +func desiredService(ctx context.Context, params Params) *corev1.Service { + name := fmt.Sprintf("%s-collector", params.Instance.Name) + + labels := collector.Labels(params.Instance) + labels["app.kubernetes.io/name"] = name + + // by coincidence, the selector is the same as the label, but note that the selector points to the deployment + // whereas 'labels' refers to the service + selector := labels + + config, err := adapters.ConfigFromString(params.Instance.Spec.Config) + if err != nil { + params.Log.Error(err, "couldn't extract the configuration from the context") + return nil + } + + ports, err := adapters.ConfigToReceiverPorts(params.Log, config) + if err != nil { + params.Log.Error(err, "couldn't build the service for this instance") + return nil + } + + if len(params.Instance.Spec.Ports) > 0 { + // we should add all the ports from the CR + // there are two cases where problems might occur: + // 1) when the port number is already being used by a receiver + // 2) same, but for the port name + // + // in the first case, we remove the port we inferred from the list + // in the second case, we rename our inferred port to something like "port-%d" + portNumbers, portNames := extractPortNumbersAndNames(params.Instance.Spec.Ports) + resultingInferredPorts := []corev1.ServicePort{} + for _, inferred := range ports { + if filtered := filterPort(params.Log, inferred, portNumbers, portNames); filtered != nil { + resultingInferredPorts = append(resultingInferredPorts, *filtered) + } + } + + ports = append(params.Instance.Spec.Ports, resultingInferredPorts...) + } + + // if we have no ports, we don't need a service + if len(ports) == 0 { + params.Log.V(1).Info("the instance's configuration didn't yield any ports to open, skipping service", "instance.name", params.Instance.Name, "instance.namespace", params.Instance.Namespace) + return nil + } + + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: params.Instance.Namespace, + Labels: labels, + Annotations: params.Instance.Annotations, + }, + Spec: corev1.ServiceSpec{ + Selector: selector, + ClusterIP: "", + Ports: ports, + }, + } +} + +func headless(ctx context.Context, params Params) *corev1.Service { + h := desiredService(ctx, params) + if h == nil { + return nil + } + + h.Name = fmt.Sprintf("%s-headless", h.Name) + h.Spec.ClusterIP = "None" + return h +} + +func monitoringService(ctx context.Context, params Params) *corev1.Service { + name := fmt.Sprintf("%s-collector-monitoring", params.Instance.Name) + + labels := collector.Labels(params.Instance) + labels["app.kubernetes.io/name"] = name + + selector := collector.Labels(params.Instance) + selector["app.kubernetes.io/name"] = fmt.Sprintf("%s-collector", params.Instance.Name) + + return &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: params.Instance.Namespace, + Labels: labels, + Annotations: params.Instance.Annotations, + }, + Spec: corev1.ServiceSpec{ + Selector: selector, + ClusterIP: "", + Ports: []corev1.ServicePort{{ + Name: "monitoring", + Port: 8888, + }}, + }, + } +} + +func expectedServices(ctx context.Context, params Params, expected []corev1.Service) error { + for _, obj := range expected { + desired := obj + + controllerutil.SetControllerReference(¶ms.Instance, &desired, params.Scheme) + + existing := &corev1.Service{} + nns := types.NamespacedName{Namespace: desired.Namespace, Name: desired.Name} + err := params.Client.Get(ctx, nns, existing) + if err != nil && k8serrors.IsNotFound(err) { + if err := params.Client.Create(ctx, &desired); err != nil { + return fmt.Errorf("failed to create: %w", err) + } + params.Log.V(2).Info("created", "service.name", desired.Name, "service.namespace", desired.Namespace) + continue + } else if err != nil { + return fmt.Errorf("failed to get: %w", err) + } + + // it exists already, merge the two if the end result isn't identical to the existing one + updated := existing.DeepCopy() + if updated.Annotations == nil { + updated.Annotations = map[string]string{} + } + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences + + for k, v := range desired.ObjectMeta.Annotations { + updated.ObjectMeta.Annotations[k] = v + } + for k, v := range desired.ObjectMeta.Labels { + updated.ObjectMeta.Labels[k] = v + } + + if err := params.Client.Update(ctx, updated); err != nil { + return fmt.Errorf("failed to apply changes: %w", err) + } + + params.Log.V(2).Info("applied", "service.name", desired.Name, "service.namespace", desired.Namespace) + } + + return nil +} + +func deleteServices(ctx context.Context, params Params, expected []corev1.Service) error { + opts := []client.ListOption{ + client.InNamespace(params.Instance.Namespace), + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.Instance.Namespace, params.Instance.Name), + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }), + } + list := &corev1.ServiceList{} + if err := params.Client.List(ctx, list, opts...); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + + for _, existing := range list.Items { + del := true + for _, keep := range expected { + if keep.Name == existing.Name && keep.Namespace == existing.Namespace { + del = false + } + } + + if del { + if err := params.Client.Delete(ctx, &existing); err != nil { + return fmt.Errorf("failed to delete: %w", err) + } + params.Log.V(2).Info("deleted", "service.name", existing.Name, "service.namespace", existing.Namespace) + } + } + + return nil +} + +func filterPort(logger logr.Logger, candidate corev1.ServicePort, portNumbers map[int32]bool, portNames map[string]bool) *corev1.ServicePort { + if portNumbers[candidate.Port] { + return nil + } + + // do we have the port name there already? + if portNames[candidate.Name] { + // there's already a port with the same name! do we have a 'port-%d' already? + fallbackName := fmt.Sprintf("port-%d", candidate.Port) + if portNames[fallbackName] { + // that wasn't expected, better skip this port + logger.V(2).Info("a port name specified in the CR clashes with an inferred port name, and the fallback port name clashes with another port name! Skipping this port.", + "inferred-port-name", candidate.Name, + "fallback-port-name", fallbackName, + ) + return nil + } + + candidate.Name = fallbackName + return &candidate + } + + // this port is unique, return as is + return &candidate +} + +func extractPortNumbersAndNames(ports []corev1.ServicePort) (map[int32]bool, map[string]bool) { + numbers := map[int32]bool{} + names := map[string]bool{} + + for _, port := range ports { + numbers[port.Port] = true + names[port.Name] = true + } + + return numbers, names +} diff --git a/pkg/collector/reconcile/serviceaccount.go b/pkg/collector/reconcile/serviceaccount.go new file mode 100644 index 0000000000..a2d67b25da --- /dev/null +++ b/pkg/collector/reconcile/serviceaccount.go @@ -0,0 +1,152 @@ +// Copyright The OpenTelemetry Authors +// +// 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 reconcile + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector" +) + +// ServiceAccounts reconciles the service account(s) required for the instance in the current context +func ServiceAccounts(ctx context.Context, params Params) error { + desired := []corev1.ServiceAccount{ + desiredServiceAccount(ctx, params), + } + + // first, handle the create/update parts + if err := expectedServiceAccounts(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the expected service accounts: %v", err) + } + + // then, delete the extra objects + if err := deleteServiceAccounts(ctx, params, desired); err != nil { + return fmt.Errorf("failed to reconcile the service accounts to be deleted: %v", err) + } + + return nil +} + +func desiredServiceAccount(ctx context.Context, params Params) corev1.ServiceAccount { + name := fmt.Sprintf("%s-collector", params.Instance.Name) + + labels := collector.Labels(params.Instance) + labels["app.kubernetes.io/name"] = name + + return corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: params.Instance.Namespace, + Labels: labels, + Annotations: params.Instance.Annotations, + }, + } +} + +func expectedServiceAccounts(ctx context.Context, params Params, expected []corev1.ServiceAccount) error { + for _, obj := range expected { + desired := obj + + controllerutil.SetControllerReference(¶ms.Instance, &desired, params.Scheme) + + existing := &corev1.ServiceAccount{} + nns := types.NamespacedName{Namespace: desired.Namespace, Name: desired.Name} + err := params.Client.Get(ctx, nns, existing) + if err != nil && k8serrors.IsNotFound(err) { + if err := params.Client.Create(ctx, &desired); err != nil { + return fmt.Errorf("failed to create: %w", err) + } + params.Log.V(2).Info("created", "serviceaccount.name", desired.Name, "serviceaccount.namespace", desired.Namespace) + continue + } else if err != nil { + return fmt.Errorf("failed to get: %w", err) + } + + // it exists already, merge the two if the end result isn't identical to the existing one + updated := existing.DeepCopy() + if updated.Annotations == nil { + updated.Annotations = map[string]string{} + } + if updated.Labels == nil { + updated.Labels = map[string]string{} + } + updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences + + for k, v := range desired.ObjectMeta.Annotations { + updated.ObjectMeta.Annotations[k] = v + } + for k, v := range desired.ObjectMeta.Labels { + updated.ObjectMeta.Labels[k] = v + } + + if err := params.Client.Update(ctx, updated); err != nil { + return fmt.Errorf("failed to apply changes: %w", err) + } + + params.Log.V(2).Info("applied", "serviceaccount.name", desired.Name, "serviceaccount.namespace", desired.Namespace) + } + + return nil +} + +func deleteServiceAccounts(ctx context.Context, params Params, expected []corev1.ServiceAccount) error { + opts := []client.ListOption{ + client.InNamespace(params.Instance.Namespace), + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.Instance.Namespace, params.Instance.Name), + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }), + } + list := &corev1.ServiceAccountList{} + if err := params.Client.List(ctx, list, opts...); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + + for _, existing := range list.Items { + del := true + for _, keep := range expected { + if keep.Name == existing.Name && keep.Namespace == existing.Namespace { + del = false + } + } + + if del { + if err := params.Client.Delete(ctx, &existing); err != nil { + return fmt.Errorf("failed to delete: %w", err) + } + params.Log.V(2).Info("deleted", "serviceaccount.name", existing.Name, "serviceaccount.namespace", existing.Namespace) + } + } + + return nil +} + +// ServiceAccountNameFor returns the name of the service account for the given context +func ServiceAccountNameFor(instance v1alpha1.OpenTelemetryCollector) string { + if len(instance.Spec.ServiceAccount) == 0 { + return fmt.Sprintf("%s-collector", instance.Name) + } + + return instance.Spec.ServiceAccount +} diff --git a/pkg/collector/upgrade/upgrade.go b/pkg/collector/upgrade/upgrade.go new file mode 100644 index 0000000000..e1b8b0bd38 --- /dev/null +++ b/pkg/collector/upgrade/upgrade.go @@ -0,0 +1,81 @@ +package upgrade + +import ( + "context" + "fmt" + "reflect" + + "github.com/go-logr/logr" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" +) + +// ManagedInstances finds all the otelcol instances for the current operator and upgrades them, if necessary +func ManagedInstances(ctx context.Context, logger logr.Logger, cl client.Client) error { + logger.Info("looking for managed instances to upgrade") + + opts := []client.ListOption{ + client.MatchingLabels(map[string]string{ + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }), + } + list := &v1alpha1.OpenTelemetryCollectorList{} + if err := cl.List(ctx, list, opts...); err != nil { + return fmt.Errorf("failed to list: %w", err) + } + + for _, j := range list.Items { + otelcol, err := ManagedInstance(ctx, logger, cl, &j) + if err != nil { + // nothing to do at this level, just go to the next instance + continue + } + + if !reflect.DeepEqual(otelcol, j) { + // the resource update overrides the status, so, keep it so that we can reset it later + st := otelcol.Status + if err := cl.Update(ctx, otelcol); err != nil { + logger.Error(err, "failed to apply changes to instance", "name", otelcol.Name, "namespace", otelcol.Namespace) + continue + } + + // the status object requires its own update + otelcol.Status = st + if err := cl.Status().Update(ctx, otelcol); err != nil { + logger.Error(err, "failed to apply changes to instance's status object", "name", otelcol.Name, "namespace", otelcol.Namespace) + continue + } + + logger.Info("instance upgraded", "name", otelcol.Name, "namespace", otelcol.Namespace, "version", otelcol.Status.Version) + } + } + + if len(list.Items) == 0 { + logger.Info("no instances to upgrade") + } + + return nil +} + +// ManagedInstance performs the necessary changes to bring the given otelcol instance to the current version +func ManagedInstance(ctx context.Context, logger logr.Logger, cl client.Client, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) { + if v, ok := versions[otelcol.Status.Version]; ok { + // we don't need to run the upgrade function for the version 'v', only the next ones + for n := v.next; n != nil; n = n.next { + // performs the upgrade to version 'n' + upgraded, err := n.upgrade(cl, otelcol) + if err != nil { + logger.Error(err, "failed to upgrade managed otelcol instances", "name", otelcol.Name, "namespace", otelcol.Namespace) + return otelcol, err + } + + logger.V(1).Info("step upgrade", "name", otelcol.Name, "namespace", otelcol.Namespace, "version", n.Tag) + upgraded.Status.Version = n.Tag + otelcol = upgraded + } + } + + logger.V(1).Info("final version", "name", otelcol.Name, "namespace", otelcol.Namespace, "version", otelcol.Status.Version) + return otelcol, nil +} diff --git a/pkg/collector/upgrade/upgrade_suite_test.go b/pkg/collector/upgrade/upgrade_suite_test.go new file mode 100644 index 0000000000..c49710cfe8 --- /dev/null +++ b/pkg/collector/upgrade/upgrade_suite_test.go @@ -0,0 +1,57 @@ +package upgrade_test + +import ( + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "k8s.io/client-go/rest" + "k8s.io/kubectl/pkg/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" +) + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestUpgrade(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Upgrade Suite") +} + +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 = v1alpha1.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/collector/upgrade/upgrade_test.go b/pkg/collector/upgrade/upgrade_test.go new file mode 100644 index 0000000000..9b61d484b5 --- /dev/null +++ b/pkg/collector/upgrade/upgrade_test.go @@ -0,0 +1,56 @@ +package upgrade_test + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" + "github.com/open-telemetry/opentelemetry-operator/pkg/collector/upgrade" +) + +var _ = Describe("Upgrade", func() { + logger := logf.Log.WithName("unit-tests") + + It("should upgrade to the latest", func() { + // prepare + nsn := types.NamespacedName{Name: "my-instance", Namespace: "default"} + existing := v1alpha1.OpenTelemetryCollector{ + ObjectMeta: metav1.ObjectMeta{ + Name: nsn.Name, + Namespace: nsn.Namespace, + Labels: map[string]string{ + "app.kubernetes.io/managed-by": "opentelemetry-operator", + }, + }, + } + existing.Status.Version = "0.0.1" // this is the first version we have an upgrade function + err := k8sClient.Create(context.Background(), &existing) + Expect(err).To(Succeed()) + + err = k8sClient.Status().Update(context.Background(), &existing) + Expect(err).To(Succeed()) + + // sanity check + persisted := &v1alpha1.OpenTelemetryCollector{} + err = k8sClient.Get(context.Background(), nsn, persisted) + Expect(err).To(Succeed()) + Expect(persisted.Status.Version).To(Equal("0.0.1")) + + // test + err = upgrade.ManagedInstances(context.Background(), logger, k8sClient) + Expect(err).To(Succeed()) + + // verify + err = k8sClient.Get(context.Background(), nsn, persisted) + Expect(err).To(Succeed()) + Expect(persisted.Status.Version).To(Equal(upgrade.Latest.Tag)) + + // cleanup + Expect(k8sClient.Delete(context.Background(), &existing)) + }) +}) diff --git a/pkg/collector/upgrade/v0_2_0.go b/pkg/collector/upgrade/v0_2_0.go new file mode 100644 index 0000000000..e8f01e4159 --- /dev/null +++ b/pkg/collector/upgrade/v0_2_0.go @@ -0,0 +1,13 @@ +package upgrade + +import ( + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" +) + +func upgrade0_2_0(cl client.Client, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) { + // this has the same content as `noop`, but it's added a separate function + // to serve as template for versions with an actual upgrade procedure + return otelcol, nil +} diff --git a/pkg/collector/upgrade/versions.go b/pkg/collector/upgrade/versions.go new file mode 100644 index 0000000000..f1305e05fe --- /dev/null +++ b/pkg/collector/upgrade/versions.go @@ -0,0 +1,35 @@ +package upgrade + +import ( + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/open-telemetry/opentelemetry-operator/api/v1alpha1" +) + +// Version represents a known OpenTelemetry Collector version +type Version struct { + // Tag represents the tag for this version, like: 0.0.1 + Tag string + + upgrade func(cl client.Client, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) + next *Version +} + +var ( + v0_0_1 = Version{Tag: "0.0.1", upgrade: noop, next: &v0_0_2} + v0_0_2 = Version{Tag: "0.0.2", upgrade: noop, next: &v0_2_0} + v0_2_0 = Version{Tag: "0.2.0", upgrade: upgrade0_2_0} + + // Latest represents the latest known version for the OpenTelemetry Collector + Latest = &v0_2_0 + + versions = map[string]Version{ + v0_0_1.Tag: v0_0_1, + v0_0_2.Tag: v0_0_2, + v0_2_0.Tag: v0_2_0, + } +) + +func noop(cl client.Client, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) { + return otelcol, nil +} diff --git a/pkg/controller/add_opentelemetrycollector.go b/pkg/controller/add_opentelemetrycollector.go deleted file mode 100644 index bda65864ba..0000000000 --- a/pkg/controller/add_opentelemetrycollector.go +++ /dev/null @@ -1,10 +0,0 @@ -package controller - -import ( - "github.com/open-telemetry/opentelemetry-operator/pkg/controller/opentelemetrycollector" -) - -func init() { - // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. - AddToManagerFuncs = append(AddToManagerFuncs, opentelemetrycollector.Add) -} diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go deleted file mode 100644 index 7c069f3ee6..0000000000 --- a/pkg/controller/controller.go +++ /dev/null @@ -1,18 +0,0 @@ -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/empty_test.go b/pkg/controller/empty_test.go deleted file mode 100644 index 6323e14cc3..0000000000 --- a/pkg/controller/empty_test.go +++ /dev/null @@ -1,2 +0,0 @@ -// this file exists to force the coverage tool to count this directory -package controller diff --git a/pkg/controller/opentelemetrycollector/labels.go b/pkg/controller/opentelemetrycollector/labels.go deleted file mode 100644 index cb03194dbb..0000000000 --- a/pkg/controller/opentelemetrycollector/labels.go +++ /dev/null @@ -1,29 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// commonLabels return the common labels to all objects that are part of a managed OpenTelemetryCollector -func commonLabels(ctx context.Context) map[string]string { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - - // new map every time, so that we don't touch the instance's label - base := map[string]string{} - if nil != instance.Labels { - for k, v := range instance.Labels { - base[k] = v - } - } - - base["app.kubernetes.io/managed-by"] = "opentelemetry-operator" - base["app.kubernetes.io/instance"] = fmt.Sprintf("%s.%s", instance.Namespace, instance.Name) - base["app.kubernetes.io/part-of"] = "opentelemetry" - base["app.kubernetes.io/component"] = "opentelemetry-collector" - - return base -} diff --git a/pkg/controller/opentelemetrycollector/labels_test.go b/pkg/controller/opentelemetrycollector/labels_test.go deleted file mode 100644 index b718aa1899..0000000000 --- a/pkg/controller/opentelemetrycollector/labels_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -func TestNilLabels(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-otelcol", - Namespace: "observability", - Labels: nil, - }, - } - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, instance) - - // test - labels := commonLabels(ctx) - - // verify - assert.NotNil(t, labels) - assert.Contains(t, labels, "app.kubernetes.io/managed-by") - assert.Contains(t, labels, "app.kubernetes.io/instance") - assert.Contains(t, labels, "app.kubernetes.io/part-of") - assert.Contains(t, labels, "app.kubernetes.io/component") -} - -func TestInstanceName(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-otelcol", - Namespace: "observability", - Labels: nil, - }, - } - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, instance) - - // test - labels := commonLabels(ctx) - - // verify - assert.Equal(t, labels["app.kubernetes.io/instance"], "observability.my-otelcol") -} diff --git a/pkg/controller/opentelemetrycollector/main_test.go b/pkg/controller/opentelemetrycollector/main_test.go deleted file mode 100644 index d1a82dac44..0000000000 --- a/pkg/controller/opentelemetrycollector/main_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "os" - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -var ( - instance *v1alpha1.OpenTelemetryCollector - ctx context.Context - schem *runtime.Scheme - baseTestConfig = `receivers: - first: - endpoint: localhost:1234 -` -) - -// TestMain ensures that all tests in this package have a fresh and sane instance of the common resources -func TestMain(m *testing.M) { - schem = scheme.Scheme - schem.AddKnownTypes(v1alpha1.SchemeGroupVersion, &v1alpha1.OpenTelemetryCollector{}) - - gvk := v1alpha1.SchemeGroupVersion.WithKind("OpenTelemetryCollector") - instance = &v1alpha1.OpenTelemetryCollector{ - TypeMeta: metav1.TypeMeta{ - // TypeMeta is added by Kubernetes, there's no need for consumers to set this manually - Kind: gvk.Kind, - APIVersion: gvk.GroupVersion().String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "my-otelcol", - Namespace: "observability", - Labels: map[string]string{"custom-label": "custom-value"}, - Annotations: map[string]string{"custom-annotation": "custom-annotation-value"}, - }, - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Config: baseTestConfig, - }, - } - ctx = context.WithValue(context.Background(), opentelemetry.ContextInstance, instance) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - os.Exit(m.Run()) -} diff --git a/pkg/controller/opentelemetrycollector/opentelemetrycollector_controller.go b/pkg/controller/opentelemetrycollector/opentelemetrycollector_controller.go deleted file mode 100644 index 13cc46aecc..0000000000 --- a/pkg/controller/opentelemetrycollector/opentelemetrycollector_controller.go +++ /dev/null @@ -1,42 +0,0 @@ -package opentelemetrycollector - -import ( - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - "sigs.k8s.io/controller-runtime/pkg/source" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -var log = logf.Log.WithName("controller_opentelemetrycollector") - -// Add creates a new OpenTelemetryCollector 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 { - r, err := WithManager(mgr) - if err != nil { - return err - } - - return add(mgr, r) -} - -// 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("opentelemetrycollector-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - - // Watch for changes to primary resource OpenTelemetryCollector - err = c.Watch(&source.Kind{Type: &v1alpha1.OpenTelemetryCollector{}}, &handler.EnqueueRequestForObject{}) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/controller/opentelemetrycollector/reconcile.go b/pkg/controller/opentelemetrycollector/reconcile.go deleted file mode 100644 index 8df60d1a63..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile.go +++ /dev/null @@ -1,147 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - "time" - - "k8s.io/apimachinery/pkg/api/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" -) - -// blank assignment to verify that ReconcileOpenTelemetryCollector implements reconcile.Reconciler -var _ reconcile.Reconciler = &ReconcileOpenTelemetryCollector{} - -// ReconcileOpenTelemetryCollector reconciles a OpenTelemetryCollector object -type ReconcileOpenTelemetryCollector struct { - // This client, initialized using mgr.Client() above, is a split client - // that reads objects from the cache and writes to the apiserver - scheme *runtime.Scheme - - // the clients that compose this reconciler - clientset *client.Clientset - - // the list of reconciliation functions to execute - reconcileFuncs []func(context.Context) error -} - -// WithManager creates a new reconciler based on the manager information -func WithManager(manager manager.Manager) (*ReconcileOpenTelemetryCollector, error) { - cl, err := client.ForManager(manager) - if err != nil { - return nil, err - } - - return New(manager.GetScheme(), cl), nil -} - -// New constructs a ReconcileOpenTelemetryCollector based on the client and scheme, with the default reconciliation functions -func New(scheme *runtime.Scheme, clientset *client.Clientset) *ReconcileOpenTelemetryCollector { - r := &ReconcileOpenTelemetryCollector{ - scheme: scheme, - clientset: clientset, - } - r.reconcileFuncs = []func(context.Context) error{ - r.reconcileServiceAccount, - r.reconcileConfigMap, - r.reconcileService, - r.reconcileDeployment, - r.reconcileDaemonSet, - r.reconcileServiceMonitor, - } - - return r -} - -// Reconcile reads that state of the cluster for a OpenTelemetryCollector object and makes changes based on the state read -// and what is in the OpenTelemetryCollector.Spec -func (r *ReconcileOpenTelemetryCollector) Reconcile(request reconcile.Request) (reconcile.Result, error) { - // the base context for this whole reconciliation loop - ctx := context.Background() - - reqLogger := log.WithValues( - "Request.Namespace", request.Namespace, - "Request.Name", request.Name, - "Request.ID", time.Now().UTC().UnixNano(), - ) - reqLogger.Info("Reconciling OpenTelemetryCollector") - - otelCols := r.clientset.OpenTelemetry.OpentelemetryV1alpha1().OpenTelemetryCollectors(request.Namespace) - - // Fetch the OpenTelemetryCollector instance - instance, err := otelCols.Get(ctx, request.Name, v1.GetOptions{}) - if 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. - // Return and don't requeue - reqLogger.Info("OpenTelemetryCollector was deleted, reconciliation terminated") - return reconcile.Result{}, nil - } - // Error reading the object - requeue the request. - return reconcile.Result{}, err - } - - // set the execution context for this reconcile loop - ctx = context.WithValue(ctx, opentelemetry.ContextInstance, instance) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, reqLogger) - - if err := r.applyUpgrades(ctx); err != nil { - reqLogger.Error(err, "failed to upgrade the custom resource and its underlying resources, reconciliation aborted") - return reconcile.Result{}, err - } - - if err := r.handleReconcile(ctx); err != nil { - reqLogger.Error(err, "failed to reconcile custom resource") - return reconcile.Result{}, err - } - - // update the status object, which might have also been updated - if instance, err = otelCols.UpdateStatus(ctx, instance, v1.UpdateOptions{}); err != nil { - reqLogger.Error(err, "failed to store the custom resource's status") - return reconcile.Result{}, err - } - - // apply it back, as it might have been updated - if _, err := otelCols.Update(ctx, instance, v1.UpdateOptions{}); err != nil { - reqLogger.Error(err, "failed to store back the custom resource") - return reconcile.Result{}, err - } - - reqLogger.Info("Finished reconciling OpenTelemetryCollector") - return reconcile.Result{}, nil -} - -// handleReconcile compares the existing state vs. the expected state and performs the necessary actions to make the two match -func (r *ReconcileOpenTelemetryCollector) handleReconcile(ctx context.Context) error { - if nil == r.reconcileFuncs { - // nothing to do! - return nil - } - - for _, f := range r.reconcileFuncs { - if err := f(ctx); err != nil { - return fmt.Errorf("reconciliation failed: %v", err) - } - } - - return nil -} - -// setControllerReference should be used by the individual reconcile functions to establish the ownership of the underlying resources -func (r *ReconcileOpenTelemetryCollector) setControllerReference(ctx context.Context, object v1.Object) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - return controllerutil.SetControllerReference(instance, object, r.scheme) -} - -func resourceName(instanceName string) string { - return fmt.Sprintf("%s-collector", instanceName) -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_configmap.go b/pkg/controller/opentelemetrycollector/reconcile_configmap.go deleted file mode 100644 index 3d4864bb0c..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_configmap.go +++ /dev/null @@ -1,140 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// reconcileConfigMap reconciles the config map(s) required for the instance in the current context -func (r *ReconcileOpenTelemetryCollector) reconcileConfigMap(ctx context.Context) error { - desired := []*corev1.ConfigMap{ - configMap(ctx), - } - - // first, handle the create/update parts - if err := r.reconcileExpectedConfigMaps(ctx, desired); err != nil { - return fmt.Errorf("failed to reconcile the expected deployments: %v", err) - } - - // then, delete the extra objects - if err := r.deleteConfigMaps(ctx, desired); err != nil { - return fmt.Errorf("failed to reconcile the deployments to be deleted: %v", err) - } - - return nil -} - -func configMap(ctx context.Context) *corev1.ConfigMap { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - name := fmt.Sprintf("%s-collector", instance.Name) - - labels := commonLabels(ctx) - labels["app.kubernetes.io/name"] = name - - return &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - Labels: labels, - Annotations: instance.Annotations, - }, - Data: map[string]string{ - opentelemetry.CollectorConfigMapEntry: instance.Spec.Config, - }, - } -} - -func (r *ReconcileOpenTelemetryCollector) reconcileExpectedConfigMaps(ctx context.Context, expected []*corev1.ConfigMap) error { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - for _, obj := range expected { - desired := obj - - // #nosec G104 (CWE-703): Errors unhandled. - r.setControllerReference(ctx, desired) - - cmaps := r.clientset.Kubernetes.CoreV1().ConfigMaps(desired.Namespace) - - existing, err := cmaps.Get(ctx, desired.Name, metav1.GetOptions{}) - if err != nil && errors.IsNotFound(err) { - if desired, err = cmaps.Create(ctx, desired, metav1.CreateOptions{}); err != nil { - return fmt.Errorf("failed to create: %v", err) - } - - logger.WithValues("configmap.name", desired.Name, "configmap.namespace", desired.Namespace).V(2).Info("created") - continue - } else if err != nil { - return fmt.Errorf("failed to get: %v", err) - } - - // it exists already, merge the two if the end result isn't identical to the existing one - updated := existing.DeepCopy() - if updated.Annotations == nil { - updated.Annotations = map[string]string{} - } - if updated.Labels == nil { - updated.Labels = map[string]string{} - } - - updated.Data = desired.Data - updated.BinaryData = desired.BinaryData - updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences - - for k, v := range desired.ObjectMeta.Annotations { - updated.ObjectMeta.Annotations[k] = v - } - for k, v := range desired.ObjectMeta.Labels { - updated.ObjectMeta.Labels[k] = v - } - - if updated, err = cmaps.Update(ctx, updated, metav1.UpdateOptions{}); err != nil { - return fmt.Errorf("failed to apply changes: %v", err) - } - logger.V(2).Info("applied", "configmap.name", desired.Name, "configmap.namespace", desired.Namespace) - } - - return nil -} - -func (r *ReconcileOpenTelemetryCollector) deleteConfigMaps(ctx context.Context, expected []*corev1.ConfigMap) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - cmaps := r.clientset.Kubernetes.CoreV1().ConfigMaps(instance.Namespace) - - opts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", instance.Namespace, instance.Name), - "app.kubernetes.io/managed-by": "opentelemetry-operator", - }).String(), - } - list, err := cmaps.List(ctx, opts) - if err != nil { - return fmt.Errorf("failed to list: %v", err) - } - - for _, existing := range list.Items { - del := true - for _, keep := range expected { - if keep.Name == existing.Name && keep.Namespace == existing.Namespace { - del = false - } - } - - if del { - if err := cmaps.Delete(ctx, existing.Name, metav1.DeleteOptions{}); err != nil { - return fmt.Errorf("failed to delete: %v", err) - } - logger.V(2).Info("deleted", "configmap.name", existing.Name, "configmap.namespace", existing.Namespace) - } - } - - return nil -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_configmap_test.go b/pkg/controller/opentelemetrycollector/reconcile_configmap_test.go deleted file mode 100644 index 82a4106dc0..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_configmap_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -func TestProperConfigMap(t *testing.T) { - // test - c := configMap(ctx) - - // verify - assert.Equal(t, c.Name, "my-otelcol-collector") - assert.Equal(t, c.Annotations["custom-annotation"], "custom-annotation-value") - assert.Equal(t, c.Labels["custom-label"], "custom-value") - assert.Equal(t, c.Labels["app.kubernetes.io/name"], c.Name) - assert.Equal(t, c.Data[opentelemetry.CollectorConfigMapEntry], baseTestConfig) -} - -func TestProperReconcileConfigMap(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - - // test - _, err := reconciler.Reconcile(req) - assert.NoError(t, err) - - // verify - list, err := clients.Kubernetes.CoreV1().ConfigMaps(instance.Namespace).List(context.Background(), metav1.ListOptions{}) - assert.NoError(t, err) - - // we assert the correctness of the service in another test - assert.Len(t, list.Items, 1) - - // we assert the correctness of the reference in another test - assert.Len(t, list.Items[0].OwnerReferences, 1) -} - -func TestUpdateConfigMap(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - reconciler.Reconcile(req) - - // sanity check - name := resourceName(instance.Name) - persisted, err := clients.Kubernetes.CoreV1().ConfigMaps(instance.Namespace).Get(context.Background(), name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Equal(t, baseTestConfig, persisted.Data[opentelemetry.CollectorConfigMapEntry]) - - // prepare the test object - updated := *instance - updated.Spec.Config = "updated-config-map" - - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, &updated) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - // test - reconciler.reconcileConfigMap(ctx) - - // verify - persisted, err = clients.Kubernetes.CoreV1().ConfigMaps(instance.Namespace).Get(context.Background(), name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Equal(t, "updated-config-map", persisted.Data[opentelemetry.CollectorConfigMapEntry]) -} - -func TestDeleteExtraConfigMap(t *testing.T) { - // prepare - c := configMap(ctx) - c.Name = "extra-config-map" - c.Namespace = instance.Namespace - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.CoreV1().ConfigMaps(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - - // test - err = reconciler.reconcileConfigMap(ctx) - assert.NoError(t, err) - - // verify - persisted, err = clients.Kubernetes.CoreV1().ConfigMaps(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.Nil(t, persisted) - assert.Error(t, err) // not found -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_daemonset.go b/pkg/controller/opentelemetrycollector/reconcile_daemonset.go deleted file mode 100644 index a0c37feb28..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_daemonset.go +++ /dev/null @@ -1,213 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - "github.com/spf13/viper" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// reconcileDaemonSet reconciles the daemonSet(s) required for the instance in the current context -func (r *ReconcileOpenTelemetryCollector) reconcileDaemonSet(ctx context.Context) error { - desired := daemonSets(ctx) - - // first, handle the create/update parts - if err := r.reconcileExpectedDaemonSets(ctx, desired); err != nil { - return fmt.Errorf("failed to reconcile the expected daemonSets: %v", err) - } - - // then, delete the extra objects - if err := r.deleteDaemonSets(ctx, desired); err != nil { - return fmt.Errorf("failed to reconcile the daemonSets to be deleted: %v", err) - } - - return nil -} - -func daemonSets(ctx context.Context) []*appsv1.DaemonSet { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - - var desired []*appsv1.DaemonSet - if instance.Spec.Mode == opentelemetry.ModeDaemonSet { - desired = append(desired, daemonSet(ctx)) - } - - return desired -} - -func daemonSet(ctx context.Context) *appsv1.DaemonSet { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - name := resourceName(instance.Name) - - image := instance.Spec.Image - if len(image) == 0 { - image = viper.GetString(opentelemetry.OtelColImageConfigKey) - } - - labels := commonLabels(ctx) - labels["app.kubernetes.io/name"] = name - - specAnnotations := instance.Annotations - if specAnnotations == nil { - specAnnotations = map[string]string{} - } - - specAnnotations["prometheus.io/scrape"] = "true" - specAnnotations["prometheus.io/port"] = "8888" - specAnnotations["prometheus.io/path"] = "/metrics" - - argsMap := instance.Spec.Args - if argsMap == nil { - argsMap = map[string]string{} - } - - if _, exists := argsMap["config"]; exists { - logger.Info("the 'config' flag isn't allowed and is being ignored") - } - - // this effectively overrides any 'config' entry that might exist in the CR - argsMap["config"] = fmt.Sprintf("/conf/%s", opentelemetry.CollectorConfigMapEntry) - - var args []string - for k, v := range argsMap { - args = append(args, fmt.Sprintf("--%s=%s", k, v)) - } - - return &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - Labels: labels, - Annotations: instance.Annotations, - }, - Spec: appsv1.DaemonSetSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: labels, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - Annotations: specAnnotations, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "opentelemetry-collector", - Image: image, - VolumeMounts: []corev1.VolumeMount{{ - Name: name, - MountPath: "/conf", - }}, - Args: args, - }}, - Volumes: []corev1.Volume{{ - Name: name, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{Name: name}, - Items: []corev1.KeyToPath{{ - Key: opentelemetry.CollectorConfigMapEntry, - Path: opentelemetry.CollectorConfigMapEntry, - }}, - }, - }, - }}, - }, - }, - }, - } -} - -func (r *ReconcileOpenTelemetryCollector) reconcileExpectedDaemonSets(ctx context.Context, expected []*appsv1.DaemonSet) error { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - for _, obj := range expected { - desired := obj - - // #nosec G104 (CWE-703): Errors unhandled. - r.setControllerReference(ctx, desired) - - dsets := r.clientset.Kubernetes.AppsV1().DaemonSets(desired.Namespace) - - existing, err := dsets.Get(ctx, desired.Name, metav1.GetOptions{}) - if err != nil && errors.IsNotFound(err) { - if existing, err = dsets.Create(ctx, desired, metav1.CreateOptions{}); err != nil { - return fmt.Errorf("failed to create: %v", err) - } - - logger.WithValues("daemonSet.name", desired.Name, "daemonSet.namespace", desired.Namespace).V(2).Info("created") - continue - } else if err != nil { - return fmt.Errorf("failed to get: %v", err) - } - - // it exists already, merge the two if the end result isn't identical to the existing one - updated := existing.DeepCopy() - if updated.Annotations == nil { - updated.Annotations = map[string]string{} - } - if updated.Labels == nil { - updated.Labels = map[string]string{} - } - - updated.Spec = desired.Spec - updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences - - for k, v := range desired.ObjectMeta.Annotations { - updated.ObjectMeta.Annotations[k] = v - } - for k, v := range desired.ObjectMeta.Labels { - updated.ObjectMeta.Labels[k] = v - } - - if updated, err = dsets.Update(ctx, updated, metav1.UpdateOptions{}); err != nil { - return fmt.Errorf("failed to apply changes: %v", err) - } - logger.V(2).Info("applied", "daemonSet.name", desired.Name, "daemonSet.namespace", desired.Namespace) - } - - return nil -} - -func (r *ReconcileOpenTelemetryCollector) deleteDaemonSets(ctx context.Context, expected []*appsv1.DaemonSet) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - dsets := r.clientset.Kubernetes.AppsV1().DaemonSets(instance.Namespace) - - opts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", instance.Namespace, instance.Name), - "app.kubernetes.io/managed-by": "opentelemetry-operator", - }).String(), - } - list, err := dsets.List(ctx, opts) - if err != nil { - return fmt.Errorf("failed to list: %v", err) - } - - for _, existing := range list.Items { - del := true - for _, keep := range expected { - if keep.Name == existing.Name && keep.Namespace == existing.Namespace { - del = false - } - } - - if del { - if err := dsets.Delete(ctx, existing.Name, metav1.DeleteOptions{}); err != nil { - return fmt.Errorf("failed to delete: %v", err) - } - logger.V(2).Info("deleted", "daemonSet.name", existing.Name, "daemonSet.namespace", existing.Namespace) - } - } - - return nil -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_daemonset_test.go b/pkg/controller/opentelemetrycollector/reconcile_daemonset_test.go deleted file mode 100644 index aadf9045bd..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_daemonset_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/spf13/viper" - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -func TestProperDaemonSet(t *testing.T) { - // test - d := daemonSet(ctx) - - // verify - assert.Equal(t, d.Name, "my-otelcol-collector") - assert.Equal(t, d.Annotations["custom-annotation"], "custom-annotation-value") - assert.Equal(t, d.Labels["custom-label"], "custom-value") - assert.Equal(t, d.Labels["app.kubernetes.io/name"], d.Name) -} - -func TestProperDaemonSets(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{} - instance.Spec.Mode = opentelemetry.ModeDaemonSet - ctx := context.WithValue(ctx, opentelemetry.ContextInstance, instance) - - // test - d := daemonSets(ctx) - - // verify - assert.Len(t, d, 1) -} - -func TestNoDaemonSetsWhenModeDaemonSet(t *testing.T) { - // prepare - d := daemonSets(ctx) - - // verify - assert.Len(t, d, 0) -} - -func TestDaemonSetOverridesConfig(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Args: map[string]string{"config": "custom-path"}, - Mode: opentelemetry.ModeDaemonSet, - }, - } - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, instance) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - // test - d := daemonSet(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Len(t, d.Spec.Template.Spec.Containers[0].Args, 1) - assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args[0], "/conf/collector.yaml") -} - -func TestProperReconcileDaemonSet(t *testing.T) { - // prepare - instance := *instance - instance.Spec.Mode = opentelemetry.ModeDaemonSet - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(&instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - - // test - reconciler.Reconcile(req) - - // verify - list, err := clients.Kubernetes.AppsV1().DaemonSets(instance.Namespace).List(context.Background(), metav1.ListOptions{}) - assert.NoError(t, err) - - // we assert the correctness of the service in another test - assert.Len(t, list.Items, 1) - - // we assert the correctness of the reference in another test - assert.Len(t, list.Items[0].OwnerReferences, 1) -} - -func TestOverrideDaemonSetImageFromCustomResource(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Image: "myrepo/custom-image:version", - Mode: opentelemetry.ModeDaemonSet, - }, - } - ctx := context.WithValue(ctx, opentelemetry.ContextInstance, instance) - - // test - d := daemonSet(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Equal(t, "myrepo/custom-image:version", d.Spec.Template.Spec.Containers[0].Image) -} - -func TestOverrideDaemonSetImageFromCLI(t *testing.T) { - // prepare - viper.Set(opentelemetry.OtelColImageConfigKey, "myrepo/custom-image-cli:version") - defer viper.Reset() - defer opentelemetry.ResetFlagSet() - - // test - d := daemonSet(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Equal(t, "myrepo/custom-image-cli:version", d.Spec.Template.Spec.Containers[0].Image) -} - -func TestDefaultDaemonSetImage(t *testing.T) { - // prepare - opentelemetry.FlagSet() - defer opentelemetry.ResetFlagSet() - - // test - d := daemonSet(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Contains(t, d.Spec.Template.Spec.Containers[0].Image, "quay.io/opentelemetry/opentelemetry-collector") -} - -func TestUpdateDaemonSet(t *testing.T) { - // prepare - instance := *instance - instance.Spec.Mode = opentelemetry.ModeDaemonSet - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(&instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - reconciler.Reconcile(req) - - // sanity check - name := resourceName(instance.Name) - persisted, err := clients.Kubernetes.AppsV1().DaemonSets(instance.Namespace).Get(context.Background(), name, metav1.GetOptions{}) - assert.NoError(t, err) - - // prepare the test object - updated := instance - updated.Spec.Image = "custom-image" - - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, &updated) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - // test - reconciler.reconcileDaemonSet(ctx) - - // verify - persisted, err = clients.Kubernetes.AppsV1().DaemonSets(instance.Namespace).Get(context.Background(), name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Len(t, persisted.Spec.Template.Spec.Containers, 1) - assert.Equal(t, "custom-image", persisted.Spec.Template.Spec.Containers[0].Image) -} - -func TestDeleteExtraDaemonSet(t *testing.T) { - // prepare - c := daemonSet(ctx) - c.Name = "extra-daemonSet" - c.Namespace = instance.Namespace - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.AppsV1().DaemonSets(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - - // test - err = reconciler.reconcileDaemonSet(ctx) - assert.NoError(t, err) - - // verify - persisted, err = clients.Kubernetes.AppsV1().DaemonSets(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.Nil(t, persisted) - assert.Error(t, err) // not found -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_deployment.go b/pkg/controller/opentelemetrycollector/reconcile_deployment.go deleted file mode 100644 index 02b0c775a8..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_deployment.go +++ /dev/null @@ -1,227 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - "github.com/spf13/viper" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// reconcileDeployment reconciles the deployment(s) required for the instance in the current context -func (r *ReconcileOpenTelemetryCollector) reconcileDeployment(ctx context.Context) error { - desired := deployments(ctx) - - // first, handle the create/update parts - if err := r.reconcileExpectedDeployments(ctx, desired); err != nil { - return fmt.Errorf("failed to reconcile the expected deployments: %v", err) - } - - // then, delete the extra objects - if err := r.deleteDeployments(ctx, desired); err != nil { - return fmt.Errorf("failed to reconcile the deployments to be deleted: %v", err) - } - - return nil -} - -func deployments(ctx context.Context) []*appsv1.Deployment { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - - var desired []*appsv1.Deployment - if len(instance.Spec.Mode) == 0 || instance.Spec.Mode == opentelemetry.ModeDeployment { - desired = append(desired, deployment(ctx)) - } - - return desired -} - -func deployment(ctx context.Context) *appsv1.Deployment { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - name := resourceName(instance.Name) - - image := instance.Spec.Image - if len(image) == 0 { - image = viper.GetString(opentelemetry.OtelColImageConfigKey) - } - - labels := commonLabels(ctx) - labels["app.kubernetes.io/name"] = name - - specAnnotations := instance.Annotations - if specAnnotations == nil { - specAnnotations = map[string]string{} - } - - specAnnotations["prometheus.io/scrape"] = "true" - specAnnotations["prometheus.io/port"] = "8888" - specAnnotations["prometheus.io/path"] = "/metrics" - - argsMap := instance.Spec.Args - if argsMap == nil { - argsMap = map[string]string{} - } - - if _, exists := argsMap["config"]; exists { - logger.Info("the 'config' flag isn't allowed and is being ignored") - } - - // this effectively overrides any 'config' entry that might exist in the CR - argsMap["config"] = fmt.Sprintf("/conf/%s", opentelemetry.CollectorConfigMapEntry) - - var args []string - for k, v := range argsMap { - args = append(args, fmt.Sprintf("--%s=%s", k, v)) - } - - configMapVolumeName := fmt.Sprintf("otc-internal-%s", name) - volumeMounts := []corev1.VolumeMount{{ - Name: configMapVolumeName, - MountPath: "/conf", - }} - volumes := []corev1.Volume{{ - Name: configMapVolumeName, - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{Name: name}, - Items: []corev1.KeyToPath{{ - Key: opentelemetry.CollectorConfigMapEntry, - Path: opentelemetry.CollectorConfigMapEntry, - }}, - }, - }, - }} - - if len(instance.Spec.VolumeMounts) > 0 { - volumeMounts = append(volumeMounts, instance.Spec.VolumeMounts...) - } - - if len(instance.Spec.Volumes) > 0 { - volumes = append(volumes, instance.Spec.Volumes...) - } - - return &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - Labels: labels, - Annotations: instance.Annotations, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: instance.Spec.Replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: labels, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - Annotations: specAnnotations, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: ServiceAccountNameFor(ctx), - Containers: []corev1.Container{{ - Name: "opentelemetry-collector", - Image: image, - VolumeMounts: volumeMounts, - Args: args, - }}, - Volumes: volumes, - }, - }, - }, - } -} - -func (r *ReconcileOpenTelemetryCollector) reconcileExpectedDeployments(ctx context.Context, expected []*appsv1.Deployment) error { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - for _, obj := range expected { - desired := obj - - // #nosec G104 (CWE-703): Errors unhandled. - r.setControllerReference(ctx, desired) - - deps := r.clientset.Kubernetes.AppsV1().Deployments(desired.Namespace) - - existing, err := deps.Get(ctx, desired.Name, metav1.GetOptions{}) - if err != nil && errors.IsNotFound(err) { - if existing, err = deps.Create(ctx, desired, metav1.CreateOptions{}); err != nil { - return fmt.Errorf("failed to create: %v", err) - } - - logger.WithValues("deployment.name", desired.Name, "deployment.namespace", desired.Namespace).V(2).Info("created") - continue - } else if err != nil { - return fmt.Errorf("failed to get: %v", err) - } - - // it exists already, merge the two if the end result isn't identical to the existing one - updated := existing.DeepCopy() - if updated.Annotations == nil { - updated.Annotations = map[string]string{} - } - if updated.Labels == nil { - updated.Labels = map[string]string{} - } - - updated.Spec = desired.Spec - updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences - - for k, v := range desired.ObjectMeta.Annotations { - updated.ObjectMeta.Annotations[k] = v - } - for k, v := range desired.ObjectMeta.Labels { - updated.ObjectMeta.Labels[k] = v - } - - if updated, err = deps.Update(ctx, updated, metav1.UpdateOptions{}); err != nil { - return fmt.Errorf("failed to apply changes: %v", err) - } - logger.V(2).Info("applied", "deployment.name", desired.Name, "deployment.namespace", desired.Namespace) - } - - return nil -} - -func (r *ReconcileOpenTelemetryCollector) deleteDeployments(ctx context.Context, expected []*appsv1.Deployment) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - deps := r.clientset.Kubernetes.AppsV1().Deployments(instance.Namespace) - - opts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", instance.Namespace, instance.Name), - "app.kubernetes.io/managed-by": "opentelemetry-operator", - }).String(), - } - list, err := deps.List(ctx, opts) - if err != nil { - return fmt.Errorf("failed to list: %v", err) - } - - for _, existing := range list.Items { - del := true - for _, keep := range expected { - if keep.Name == existing.Name && keep.Namespace == existing.Namespace { - del = false - } - } - - if del { - if err := deps.Delete(ctx, existing.Name, metav1.DeleteOptions{}); err != nil { - return fmt.Errorf("failed to delete: %v", err) - } - logger.V(2).Info("deleted", "deployment.name", existing.Name, "deployment.namespace", existing.Namespace) - } - } - - return nil -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_deployment_test.go b/pkg/controller/opentelemetrycollector/reconcile_deployment_test.go deleted file mode 100644 index 4668da3e3d..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_deployment_test.go +++ /dev/null @@ -1,230 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/spf13/viper" - "github.com/stretchr/testify/assert" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -func TestProperDeployment(t *testing.T) { - // test - d := deployment(ctx) - - // verify - assert.Equal(t, d.Name, "my-otelcol-collector") - assert.Equal(t, d.Annotations["custom-annotation"], "custom-annotation-value") - assert.Equal(t, d.Labels["custom-label"], "custom-value") - assert.Equal(t, d.Labels["app.kubernetes.io/name"], d.Name) - assert.Equal(t, ServiceAccountNameFor(ctx), d.Spec.Template.Spec.ServiceAccountName) -} - -func TestProperDeployments(t *testing.T) { - // test - d := deployments(ctx) - - // verify - assert.Len(t, d, 1) -} - -func TestNoDeploymentsWhenModeDaemonSet(t *testing.T) { - // test - instance := &v1alpha1.OpenTelemetryCollector{} - instance.Spec.Mode = opentelemetry.ModeDaemonSet - ctx := context.WithValue(ctx, opentelemetry.ContextInstance, instance) - - // prepare - d := deployments(ctx) - - // verify - assert.Len(t, d, 0) -} - -func TestDeploymentOverridesConfig(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Args: map[string]string{"config": "custom-path"}, - }, - } - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, instance) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - // test - d := deployment(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Len(t, d.Spec.Template.Spec.Containers[0].Args, 1) - assert.Contains(t, d.Spec.Template.Spec.Containers[0].Args[0], "/conf/collector.yaml") -} - -func TestProperReconcileDeployment(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - - // test - reconciler.Reconcile(req) - - // verify - list, err := clients.Kubernetes.AppsV1().Deployments(instance.Namespace).List(context.Background(), metav1.ListOptions{}) - assert.NoError(t, err) - - // we assert the correctness of the service in another test - assert.Len(t, list.Items, 1) - - // we assert the correctness of the reference in another test - assert.Len(t, list.Items[0].OwnerReferences, 1) -} - -func TestOverrideDeploymentImageFromCustomResource(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Image: "myrepo/custom-image:version", - }, - } - ctx := context.WithValue(ctx, opentelemetry.ContextInstance, instance) - - // test - d := deployment(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Equal(t, "myrepo/custom-image:version", d.Spec.Template.Spec.Containers[0].Image) -} - -func TestOverrideDeploymentImageFromCLI(t *testing.T) { - // prepare - viper.Set(opentelemetry.OtelColImageConfigKey, "myrepo/custom-image-cli:version") - defer viper.Reset() - defer opentelemetry.ResetFlagSet() - - // test - d := deployment(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Equal(t, "myrepo/custom-image-cli:version", d.Spec.Template.Spec.Containers[0].Image) -} - -func TestDefaultDeploymentImage(t *testing.T) { - // prepare - opentelemetry.FlagSet() - defer opentelemetry.ResetFlagSet() - - // test - d := deployment(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Contains(t, d.Spec.Template.Spec.Containers[0].Image, "quay.io/opentelemetry/opentelemetry-collector") -} - -func TestUpdateDeployment(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - reconciler.Reconcile(req) - - // sanity check - name := resourceName(instance.Name) - persisted, err := clients.Kubernetes.AppsV1().Deployments(instance.Namespace).Get(context.Background(), name, metav1.GetOptions{}) - assert.NoError(t, err) - - // prepare the test object - updated := *instance - updated.Spec.Image = "custom-image" - - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, &updated) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - // test - reconciler.reconcileDeployment(ctx) - - // verify - persisted, err = clients.Kubernetes.AppsV1().Deployments(instance.Namespace).Get(context.Background(), name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Len(t, persisted.Spec.Template.Spec.Containers, 1) - assert.Equal(t, "custom-image", persisted.Spec.Template.Spec.Containers[0].Image) -} - -func TestDeleteExtraDeployment(t *testing.T) { - // prepare - c := deployment(ctx) - c.Name = "extra-deployment" - c.Namespace = instance.Namespace - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.AppsV1().Deployments(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - - // test - err = reconciler.reconcileDeployment(ctx) - assert.NoError(t, err) - - // verify - persisted, err = clients.Kubernetes.AppsV1().Deployments(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.Nil(t, persisted) - assert.Error(t, err) // not found -} - -func TestDeploymentWithVolumes(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - Spec: v1alpha1.OpenTelemetryCollectorSpec{ - Volumes: []v1.Volume{{ - Name: "tls-certs-volume", - }}, - VolumeMounts: []v1.VolumeMount{{ - Name: "tls-certs-volumemount", - }}, - }, - } - ctx := context.WithValue(ctx, opentelemetry.ContextInstance, instance) - - // test - d := deployment(ctx) - - // verify - assert.Len(t, d.Spec.Template.Spec.Volumes, 2) // config + the one from the CR - assert.Len(t, d.Spec.Template.Spec.Containers, 1) - assert.Len(t, d.Spec.Template.Spec.Containers[0].VolumeMounts, 2) // config + the one from the CR - - // the deployment should contain the volume we specified - assert.Contains(t, d.Spec.Template.Spec.Volumes, instance.Spec.Volumes[0]) - - // the deployment should contain the volumemount we specified - assert.Contains(t, d.Spec.Template.Spec.Containers[0].VolumeMounts, instance.Spec.VolumeMounts[0]) -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_service.go b/pkg/controller/opentelemetrycollector/reconcile_service.go deleted file mode 100644 index 88fff02a02..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_service.go +++ /dev/null @@ -1,267 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - errs "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - - "github.com/open-telemetry/opentelemetry-operator/pkg/adapters" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// reconcileService reconciles the service(s) required for the instance in the current context -func (r *ReconcileOpenTelemetryCollector) reconcileService(ctx context.Context) error { - svcs := []*corev1.Service{} - for _, s := range []*corev1.Service{service(ctx), monitoringService(ctx), headless(ctx)} { - // add only the non-nil to the list - if s != nil { - svcs = append(svcs, s) - } - } - - // first, handle the create/update parts - if err := r.reconcileExpectedServices(ctx, svcs); err != nil { - return fmt.Errorf("failed to reconcile the expected services: %v", err) - } - - // then, delete the extra objects - if err := r.deleteServices(ctx, svcs); err != nil { - return fmt.Errorf("failed to reconcile the services to be deleted: %v", err) - } - - return nil -} - -func service(ctx context.Context) *corev1.Service { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - - name := resourceName(instance.Name) - labels := serviceLabels(ctx, name) - - // by coincidence, the selector is the same as the label, but note that the selector points to the deployment - // whereas 'labels' refers to the service - selector := labels - - config, err := adapters.ConfigFromCtx(ctx) - if err != nil { - logger.Error(err, "couldn't extract the configuration from the context") - return nil - } - - ports, err := adapters.ConfigToReceiverPorts(ctx, config) - if err != nil { - logger.Error(err, "couldn't build the service for this instance") - return nil - } - - if len(instance.Spec.Ports) > 0 { - // we should add all the ports from the CR - // there are two cases where problems might occur: - // 1) when the port number is already being used by a receiver - // 2) same, but for the port name - // - // in the first case, we remove the port we inferred from the list - // in the second case, we rename our inferred port to something like "port-%d" - portNumbers, portNames := extractPortNumbersAndNames(instance.Spec.Ports) - resultingInferredPorts := []corev1.ServicePort{} - for _, inferred := range ports { - if filtered := filterPort(logger, inferred, portNumbers, portNames); filtered != nil { - resultingInferredPorts = append(resultingInferredPorts, *filtered) - } - } - - ports = append(instance.Spec.Ports, resultingInferredPorts...) - } - - // if we have no ports, we don't need a service - if len(ports) == 0 { - return nil - } - - return &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - Labels: labels, - Annotations: instance.Annotations, - }, - Spec: corev1.ServiceSpec{ - Selector: selector, - ClusterIP: "", - Ports: ports, - }, - } -} - -func headless(ctx context.Context) *corev1.Service { - h := service(ctx) - if h == nil { - return nil - } - - h.Name = fmt.Sprintf("%s-headless", h.Name) - h.Spec.ClusterIP = "None" - return h -} - -func monitoringService(ctx context.Context) *corev1.Service { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - name := fmt.Sprintf("%s-monitoring", resourceName(instance.Name)) - - return &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - Labels: serviceLabels(ctx, name), - Annotations: instance.Annotations, - }, - Spec: corev1.ServiceSpec{ - Selector: serviceLabels(ctx, resourceName(instance.Name)), - ClusterIP: "", - Ports: []corev1.ServicePort{{ - Name: "monitoring", - Port: 8888, - }}, - }, - } -} - -func (r *ReconcileOpenTelemetryCollector) reconcileExpectedServices(ctx context.Context, expected []*corev1.Service) error { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - for _, obj := range expected { - desired := obj - - // #nosec G104 (CWE-703): Errors unhandled. - r.setControllerReference(ctx, desired) - - svcs := r.clientset.Kubernetes.CoreV1().Services(desired.Namespace) - - existing, err := svcs.Get(ctx, desired.Name, metav1.GetOptions{}) - if err != nil && errs.IsNotFound(err) { - if desired, err = svcs.Create(ctx, desired, metav1.CreateOptions{}); err != nil { - return fmt.Errorf("failed to create: %v", err) - } - - logger.WithValues("service.name", desired.Name, "service.namespace", desired.Namespace).V(2).Info("created") - continue - } else if err != nil { - return fmt.Errorf("failed to retrieve: %v", err) - } - - // it exists already, merge the two if the end result isn't identical to the existing one - updated := existing.DeepCopy() - if updated.Annotations == nil { - updated.Annotations = map[string]string{} - } - if updated.Labels == nil { - updated.Labels = map[string]string{} - } - - // we keep the ClusterIP that got assigned by the cluster, if it's empty in the "desired" and not empty on the "current" - if desired.Spec.ClusterIP == "" && len(updated.Spec.ClusterIP) > 0 { - desired.Spec.ClusterIP = updated.Spec.ClusterIP - } - updated.Spec = desired.Spec - updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences - - for k, v := range desired.ObjectMeta.Annotations { - updated.ObjectMeta.Annotations[k] = v - } - for k, v := range desired.ObjectMeta.Labels { - updated.ObjectMeta.Labels[k] = v - } - - if updated, err = svcs.Update(ctx, updated, metav1.UpdateOptions{}); err != nil { - return fmt.Errorf("failed to apply changes to service: %v", err) - } - logger.V(2).Info("applied", "service.name", desired.Name, "service.namespace", desired.Namespace) - } - - return nil -} - -func (r *ReconcileOpenTelemetryCollector) deleteServices(ctx context.Context, expected []*corev1.Service) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - svcs := r.clientset.Kubernetes.CoreV1().Services(instance.Namespace) - - opts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", instance.Namespace, instance.Name), - "app.kubernetes.io/managed-by": "opentelemetry-operator", - }).String(), - } - list, err := svcs.List(ctx, opts) - if err != nil { - return fmt.Errorf("failed to list: %v", err) - } - - for _, existing := range list.Items { - del := true - for _, keep := range expected { - if keep.Name == existing.Name && keep.Namespace == existing.Namespace { - del = false - } - } - - if del { - if err := svcs.Delete(ctx, existing.Name, metav1.DeleteOptions{}); err != nil { - return fmt.Errorf("failed to delete: %v", err) - } - logger.V(2).Info("deleted", "service.name", existing.Name, "service.namespace", existing.Namespace) - } - } - - return nil -} - -func serviceLabels(ctx context.Context, name string) map[string]string { - labels := commonLabels(ctx) - labels["app.kubernetes.io/name"] = name - return labels -} - -func filterPort(logger logr.Logger, candidate corev1.ServicePort, portNumbers map[int32]bool, portNames map[string]bool) *corev1.ServicePort { - if portNumbers[candidate.Port] { - return nil - } - - // do we have the port name there already? - if portNames[candidate.Name] { - // there's already a port with the same name! do we have a 'port-%d' already? - fallbackName := fmt.Sprintf("port-%d", candidate.Port) - if portNames[fallbackName] { - // that wasn't expected, better skip this port - logger.V(2).Info("a port name specified in the CR clashes with an inferred port name, and the fallback port name clashes with another port name! Skipping this port.", - "inferred-port-name", candidate.Name, - "fallback-port-name", fallbackName, - ) - return nil - } - - candidate.Name = fallbackName - return &candidate - } - - // this port is unique, return as is - return &candidate -} - -func extractPortNumbersAndNames(ports []corev1.ServicePort) (map[int32]bool, map[string]bool) { - numbers := map[int32]bool{} - names := map[string]bool{} - - for _, port := range ports { - numbers[port.Port] = true - names[port.Name] = true - } - - return numbers, names -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_service_test.go b/pkg/controller/opentelemetrycollector/reconcile_service_test.go deleted file mode 100644 index 6ef3acbe4b..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_service_test.go +++ /dev/null @@ -1,275 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/intstr" - "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -var logger = logf.Log.WithName("logger") - -func TestProperService(t *testing.T) { - // test - s := service(ctx) - - // verify - assert.Equal(t, s.Name, "my-otelcol-collector") - assert.Equal(t, s.Annotations["custom-annotation"], "custom-annotation-value") - assert.Equal(t, s.Labels["custom-label"], "custom-value") - assert.Equal(t, s.Labels["app.kubernetes.io/name"], s.Name) - assert.Equal(t, s.Spec.Selector, s.Labels) // shortcut, as they are the same at this point -} - -func TestProperHeadlessService(t *testing.T) { - // test - s := headless(ctx) - - // verify - assert.Equal(t, s.Name, "my-otelcol-collector-headless") - assert.Equal(t, s.Spec.ClusterIP, "None") -} - -func TestProperMonitoringService(t *testing.T) { - // test - s := monitoringService(ctx) - - // verify - assert.Equal(t, s.Name, "my-otelcol-collector-monitoring") - assert.Len(t, s.Spec.Ports, 1) - assert.Equal(t, int32(8888), s.Spec.Ports[0].Port) -} - -func TestProperReconcileService(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - - // test - reconciler.Reconcile(req) - - // verify - list, err := clients.Kubernetes.CoreV1().Services(instance.Namespace).List(context.Background(), metav1.ListOptions{}) - assert.NoError(t, err) - - // we assert the correctness of the service in another test - assert.Len(t, list.Items, 3) - - // we assert the correctness of the reference in another test - for _, item := range list.Items { - assert.Len(t, item.OwnerReferences, 1) - } -} - -func TestUpdateService(t *testing.T) { - // prepare - c := service(ctx) - c.Namespace = instance.Namespace - - // right now, there's nothing we can do at the CR level that influences the underlying - // service object, so, we simulate a change made manually by some admin, changing the port - // from 14250 to 12345. Upon reconciliation, this change should be reverted - c.Spec.Ports = []corev1.ServicePort{ - { - Name: "jaeger-grpc", - Port: 12345, - TargetPort: intstr.FromInt(12345), - }, - } - c.Annotations = nil - c.Labels = nil - - // the cluster has assigned an IP to this service already - c.Spec.ClusterIP = "172.172.172.172" - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.CoreV1().Services(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Len(t, persisted.Spec.Ports, 1) - assert.Equal(t, int32(12345), persisted.Spec.Ports[0].Port) - - // test - err = reconciler.reconcileService(ctx) - assert.NoError(t, err) - - // verify - persisted, err = clients.Kubernetes.CoreV1().Services(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Equal(t, int32(1234), persisted.Spec.Ports[0].Port) - assert.Equal(t, "172.172.172.172", persisted.Spec.ClusterIP) // the assigned IP is kept -} - -func TestDeleteExtraService(t *testing.T) { - // prepare - c := service(ctx) - c.Name = "extra-service" - c.Namespace = instance.Namespace - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.CoreV1().Services(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - - // test - err = reconciler.reconcileService(ctx) - assert.NoError(t, err) - - // verify - persisted, err = clients.Kubernetes.CoreV1().Services(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.Error(t, err) // not found - assert.Nil(t, persisted) -} - -func TestServiceWithoutPorts(t *testing.T) { - for _, tt := range []string{ - "", - "🦄", - "receivers:\n myreceiver:\n endpoint:", - "receivers:\n myreceiver:\n endpoint: 0.0.0.0", - } { - // prepare - i := *instance - i.Spec.Config = tt - c := context.WithValue(ctx, opentelemetry.ContextInstance, &i) - - // test - s := service(c) - - // verify - assert.Nil(t, s, "expected no ports from a configuration like: %s", tt) - } -} - -func TestOverridePorts(t *testing.T) { - // prepare - i := *instance - i.Spec.Ports = []corev1.ServicePort{{ - Name: "my-port", - Port: int32(1234), - }} - c := context.WithValue(ctx, opentelemetry.ContextInstance, &i) - - // test - s := service(c) - - // verify - assert.NotNil(t, s) - assert.Len(t, s.Spec.Ports, 1) - assert.Equal(t, int32(1234), s.Spec.Ports[0].Port) - assert.Equal(t, "my-port", s.Spec.Ports[0].Name) -} - -func TestAddExplicitPorts(t *testing.T) { - for _, tt := range []struct { - name string // the test case name - instancePorts []corev1.ServicePort - expectedPorts map[int32]bool - expectedNames map[string]bool - }{ - { - name: "NewPort", - instancePorts: []corev1.ServicePort{{ - Name: "my-port", - Port: int32(1235), - }}, - // "first" (1234) comes from a receiver in .Spec.Config - expectedNames: map[string]bool{"first": false, "my-port": false}, - expectedPorts: map[int32]bool{1234: false, 1235: false}, - }, - { - name: "FallbackPortName", - instancePorts: []corev1.ServicePort{{ - Name: "first", // clashes with a receiver from .Spec.Config - Port: int32(1235), - }}, - expectedNames: map[string]bool{"port-1234": false, "first": false}, - expectedPorts: map[int32]bool{1234: false, 1235: false}, - }, - { - name: "FallbackPortNameClashes", - instancePorts: []corev1.ServicePort{ - { - Name: "first", // clashes with the port 1234 from the receiver in .Spec.Config - Port: int32(1235), - }, - { - Name: "port-1234", // the "first" port will be renamed to port-1234, clashes with this one - Port: int32(1236), - }, - }, - expectedNames: map[string]bool{"first": false, "port-1234": false}, - expectedPorts: map[int32]bool{1235: false, 1236: false}, // the inferred port 1234 is skipped - }, - { - name: "SkipExistingPortNumber", - instancePorts: []corev1.ServicePort{{ - Name: "my-port", - Port: int32(1234), - }}, - expectedNames: map[string]bool{"my-port": false}, - expectedPorts: map[int32]bool{1234: false}, - }, - } { - t.Run("TestAddExplicitPorts-"+tt.name, func(t *testing.T) { - // prepare - i := *instance - i.Spec.Ports = tt.instancePorts - c := context.WithValue(ctx, opentelemetry.ContextInstance, &i) - - // test - s := service(c) - - // verify - assert.NotNil(t, s) - - for _, p := range s.Spec.Ports { - if _, ok := tt.expectedPorts[p.Port]; !ok { - assert.Fail(t, "found a port that we didn't expect", "port number: %d", p.Port) - } - tt.expectedPorts[p.Port] = true - - if _, ok := tt.expectedNames[p.Name]; !ok { - assert.Fail(t, "found a port name that we didn't expect", "port name: %s", p.Name) - } - tt.expectedNames[p.Name] = true - } - - for k, v := range tt.expectedPorts { - assert.True(t, v, "the port %s should have been part of the result", k) - } - for k, v := range tt.expectedNames { - assert.True(t, v, "the port name %s should have been part of the result", k) - } - }) - } -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_serviceaccount.go b/pkg/controller/opentelemetrycollector/reconcile_serviceaccount.go deleted file mode 100644 index f383b28b37..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_serviceaccount.go +++ /dev/null @@ -1,148 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// reconcileServiceAccount reconciles the service(s) required for the instance in the current context -func (r *ReconcileOpenTelemetryCollector) reconcileServiceAccount(ctx context.Context) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - - svcs := []*corev1.ServiceAccount{} - if len(instance.Spec.ServiceAccount) == 0 { - // if there's no Service Account specified we create one and manage it ourselves - svcs = append(svcs, serviceAccount(ctx)) - } - - // first, handle the create/update parts - if err := r.reconcileExpectedServiceAccounts(ctx, svcs); err != nil { - return fmt.Errorf("failed to reconcile the expected service accounts: %v", err) - } - - // then, delete the extra objects - if err := r.deleteServiceAccounts(ctx, svcs); err != nil { - return fmt.Errorf("failed to reconcile the service accounts to be deleted: %v", err) - } - - return nil -} - -func serviceAccount(ctx context.Context) *corev1.ServiceAccount { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - name := resourceName(instance.Name) - - labels := commonLabels(ctx) - labels["app.kubernetes.io/name"] = name - - return &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - Labels: labels, - Annotations: instance.Annotations, - }, - } -} - -func (r *ReconcileOpenTelemetryCollector) reconcileExpectedServiceAccounts(ctx context.Context, expected []*corev1.ServiceAccount) error { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - for _, obj := range expected { - desired := obj - - // #nosec G104 (CWE-703): Errors unhandled. - r.setControllerReference(ctx, desired) - - svcs := r.clientset.Kubernetes.CoreV1().ServiceAccounts(desired.Namespace) - - existing, err := svcs.Get(ctx, desired.Name, metav1.GetOptions{}) - if err != nil && errors.IsNotFound(err) { - if desired, err = svcs.Create(ctx, desired, metav1.CreateOptions{}); err != nil { - return fmt.Errorf("failed to create: %v", err) - } - - logger.WithValues("serviceAccount.name", desired.Name, "serviceAccount.namespace", desired.Namespace).V(2).Info("created") - continue - } else if err != nil { - return fmt.Errorf("failed to retrieve: %v", err) - } - - // it exists already, merge the two if the end result isn't identical to the existing one - updated := existing.DeepCopy() - if updated.Annotations == nil { - updated.Annotations = map[string]string{} - } - if updated.Labels == nil { - updated.Labels = map[string]string{} - } - updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences - - for k, v := range desired.ObjectMeta.Annotations { - updated.ObjectMeta.Annotations[k] = v - } - for k, v := range desired.ObjectMeta.Labels { - updated.ObjectMeta.Labels[k] = v - } - - if updated, err = svcs.Update(ctx, updated, metav1.UpdateOptions{}); err != nil { - return fmt.Errorf("failed to apply changes to service account: %v", err) - } - logger.V(2).Info("applied", "serviceAccount.name", desired.Name, "serviceAccount.namespace", desired.Namespace) - } - - return nil -} - -func (r *ReconcileOpenTelemetryCollector) deleteServiceAccounts(ctx context.Context, expected []*corev1.ServiceAccount) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - svcs := r.clientset.Kubernetes.CoreV1().ServiceAccounts(instance.Namespace) - - opts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", instance.Namespace, instance.Name), - "app.kubernetes.io/managed-by": "opentelemetry-operator", - }).String(), - } - list, err := svcs.List(ctx, opts) - if err != nil { - return fmt.Errorf("failed to list: %v", err) - } - - for _, existing := range list.Items { - del := true - for _, keep := range expected { - if keep.Name == existing.Name && keep.Namespace == existing.Namespace { - del = false - } - } - - if del { - if err := svcs.Delete(ctx, existing.Name, metav1.DeleteOptions{}); err != nil { - return fmt.Errorf("failed to delete: %v", err) - } - logger.V(2).Info("deleted", "serviceAccount.name", existing.Name, "serviceAccount.namespace", existing.Namespace) - } - } - - return nil -} - -// ServiceAccountNameFor returns the name of the service account for the given context -func ServiceAccountNameFor(ctx context.Context) string { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - if len(instance.Spec.ServiceAccount) == 0 { - return serviceAccount(ctx).Name - } - - return instance.Spec.ServiceAccount -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_serviceaccount_test.go b/pkg/controller/opentelemetrycollector/reconcile_serviceaccount_test.go deleted file mode 100644 index 55addef029..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_serviceaccount_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -func TestProperServiceAccount(t *testing.T) { - // test - s := serviceAccount(ctx) - - // verify - assert.Equal(t, s.Name, "my-otelcol-collector") - assert.Equal(t, s.Annotations["custom-annotation"], "custom-annotation-value") - assert.Equal(t, s.Labels["custom-label"], "custom-value") - assert.Equal(t, s.Labels["app.kubernetes.io/name"], s.Name) -} - -func TestOverrideServiceAccountName(t *testing.T) { - // test - overridden := *instance - overridden.Spec.ServiceAccount = "custom-sa" - - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, &overridden) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - s := ServiceAccountNameFor(ctx) - - // verify - assert.Equal(t, "custom-sa", s) -} - -func TestUnmanagedServiceAccount(t *testing.T) { - // customize the CR, to override the service account name - overridden := *instance - overridden.Spec.ServiceAccount = "custom-sa" - - // build a context with an instance of our custom CR - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, &overridden) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - - c := &corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: overridden.Spec.ServiceAccount, - Namespace: instance.Namespace, - Annotations: instance.Annotations, - }, - } - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.CoreV1().ServiceAccounts(instance.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.NotNil(t, persisted) - - // test - reconciler.reconcileServiceAccount(ctx) - - // verify that the service account still exists and is not with the operator's labels - existing, err := clients.Kubernetes.CoreV1().ServiceAccounts(instance.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Nil(t, existing.Labels) - - // verify that a service account with the name that the operator would create does *not* exist - managed := serviceAccount(ctx) - managed, err = clients.Kubernetes.CoreV1().ServiceAccounts(instance.Namespace).Get(context.Background(), managed.Name, metav1.GetOptions{}) - assert.Error(t, err) // not found - assert.Nil(t, managed) -} - -func TestProperReconcileServiceAccount(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - - // test - reconciler.Reconcile(req) - - // verify - list, err := clients.Kubernetes.CoreV1().ServiceAccounts(instance.Namespace).List(context.Background(), metav1.ListOptions{}) - assert.NoError(t, err) - - // we assert the correctness of the service account in another test - assert.Len(t, list.Items, 1) - - // we assert the correctness of the reference in another test (TestSetControllerReference) - for _, item := range list.Items { - assert.Len(t, item.OwnerReferences, 1) - } -} - -func TestUpdateServiceAccount(t *testing.T) { - // prepare - c := serviceAccount(ctx) - c.Namespace = instance.Namespace - c.Labels = map[string]string{"some-key": "some-value"} - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.CoreV1().ServiceAccounts(instance.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Contains(t, persisted.Labels, "some-key") - assert.NotContains(t, persisted.Labels, "app.kubernetes.io/name") - - // test - reconciler.reconcileServiceAccount(ctx) - - // verify - persisted, err = clients.Kubernetes.CoreV1().ServiceAccounts(instance.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Contains(t, persisted.Labels, "some-key") - assert.Equal(t, persisted.Name, persisted.Labels["app.kubernetes.io/name"]) -} - -func TestDeleteExtraServiceAccount(t *testing.T) { - // prepare - c := serviceAccount(ctx) - c.Name = "extra-service" - c.Namespace = instance.Namespace - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(c), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - persisted, err := clients.Kubernetes.CoreV1().ServiceAccounts(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - - // test - err = reconciler.reconcileServiceAccount(ctx) - assert.NoError(t, err) - - // verify - persisted, err = clients.Kubernetes.CoreV1().ServiceAccounts(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.Error(t, err) // not found - assert.Nil(t, persisted) -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_servicemonitor.go b/pkg/controller/opentelemetrycollector/reconcile_servicemonitor.go deleted file mode 100644 index 909b774d5a..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_servicemonitor.go +++ /dev/null @@ -1,158 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "fmt" - - monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" - "github.com/go-logr/logr" - "github.com/spf13/viper" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" -) - -// reconcileServiceMonitor reconciles the service monitor(s) required for the instance in the current context -func (r *ReconcileOpenTelemetryCollector) reconcileServiceMonitor(ctx context.Context) error { - if !viper.GetBool(opentelemetry.SvcMonitorAvailable) { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - logger.V(2).Info("skipping reconciliation for service monitor, as the CRD isn't registered with the cluster") - return nil - } - - svcs := []*monitoringv1.ServiceMonitor{ - serviceMonitor(ctx), - } - - // first, handle the create/update parts - if err := r.reconcileExpectedServiceMonitors(ctx, svcs); err != nil { - return fmt.Errorf("failed to reconcile the expected service monitors: %v", err) - } - - // then, delete the extra objects - if err := r.deleteServiceMonitors(ctx, svcs); err != nil { - return fmt.Errorf("failed to reconcile the service monitors to be deleted: %v", err) - } - - return nil -} - -func serviceMonitor(ctx context.Context) *monitoringv1.ServiceMonitor { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - name := resourceName(instance.Name) - - labels := commonLabels(ctx) - labels["app.kubernetes.io/name"] = name - - selector := commonLabels(ctx) - selector["app.kubernetes.io/name"] = fmt.Sprintf("%s-monitoring", name) - - return &monitoringv1.ServiceMonitor{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: instance.Namespace, - Labels: labels, - Annotations: instance.Annotations, - }, - Spec: monitoringv1.ServiceMonitorSpec{ - Selector: metav1.LabelSelector{ - MatchLabels: selector, - }, - Endpoints: []monitoringv1.Endpoint{{ - Port: "monitoring", - }}, - }, - } - -} - -func (r *ReconcileOpenTelemetryCollector) reconcileExpectedServiceMonitors(ctx context.Context, expected []*monitoringv1.ServiceMonitor) error { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - - for _, obj := range expected { - desired := obj - - // #nosec G104 (CWE-703): Errors unhandled. - r.setControllerReference(ctx, desired) - - svcMons := r.clientset.Monitoring.MonitoringV1().ServiceMonitors(desired.Namespace) - - existing, err := svcMons.Get(ctx, desired.Name, metav1.GetOptions{}) - if err != nil && errors.IsNotFound(err) { - if desired, err = svcMons.Create(ctx, desired, metav1.CreateOptions{}); err != nil { - return fmt.Errorf("failed to create: %v", err) - } - - logger.WithValues("svcmon.name", desired.Name, "svcmon.namespace", desired.Namespace).V(2).Info("created") - continue - } else if err != nil { - return fmt.Errorf("failed to retrieve: %v", err) - } - - // it exists already, merge the two if the end result isn't identical to the existing one - updated := existing.DeepCopy() - if updated.Annotations == nil { - updated.Annotations = map[string]string{} - } - if updated.Labels == nil { - updated.Labels = map[string]string{} - } - - updated.Spec = desired.Spec - updated.ObjectMeta.OwnerReferences = desired.ObjectMeta.OwnerReferences - - for k, v := range desired.ObjectMeta.Annotations { - updated.ObjectMeta.Annotations[k] = v - } - for k, v := range desired.ObjectMeta.Labels { - updated.ObjectMeta.Labels[k] = v - } - - if _, err = svcMons.Update(ctx, updated, metav1.UpdateOptions{}); err != nil { - return fmt.Errorf("failed to apply changes to service monitor: %v", err) - } - logger.V(2).Info("applied", "svcmon.name", desired.Name, "svcmon.namespace", desired.Namespace) - } - - return nil -} - -func (r *ReconcileOpenTelemetryCollector) deleteServiceMonitors(ctx context.Context, expected []*monitoringv1.ServiceMonitor) error { - instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - - opts := metav1.ListOptions{ - LabelSelector: labels.SelectorFromSet(map[string]string{ - "app.kubernetes.io/instance": fmt.Sprintf("%s.%s", instance.Namespace, instance.Name), - "app.kubernetes.io/managed-by": "opentelemetry-operator", - }).String(), - } - - svcMons := r.clientset.Monitoring.MonitoringV1().ServiceMonitors(instance.Namespace) - - list, err := svcMons.List(ctx, opts) - if err != nil { - return fmt.Errorf("failed to list: %v", err) - } - - for _, existing := range list.Items { - del := true - for _, keep := range expected { - if keep.Name == existing.Name && keep.Namespace == existing.Namespace { - del = false - } - } - - if del { - if err := svcMons.Delete(ctx, existing.Name, metav1.DeleteOptions{}); err != nil { - return fmt.Errorf("failed to delete: %v", err) - } - logger.V(2).Info("deleted", "svcmon.name", existing.Name, "svcmon.namespace", existing.Namespace) - } - } - - return nil -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_servicemonitor_test.go b/pkg/controller/opentelemetrycollector/reconcile_servicemonitor_test.go deleted file mode 100644 index 0a750509d3..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_servicemonitor_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/spf13/viper" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -func TestProperServiceMonitor(t *testing.T) { - // test - s := serviceMonitor(ctx) - backingSvc := monitoringService(ctx) - - // verify - assert.Equal(t, "my-otelcol-collector", s.Name) - assert.Equal(t, "custom-annotation-value", s.Annotations["custom-annotation"]) - assert.Equal(t, "custom-value", s.Labels["custom-label"]) - assert.Equal(t, s.Name, s.Labels["app.kubernetes.io/name"]) - assert.Equal(t, backingSvc.Labels, s.Spec.Selector.MatchLabels) -} - -func TestProperReconcileServiceMonitor(t *testing.T) { - // prepare - viper.Set(opentelemetry.SvcMonitorAvailable, true) - defer viper.Reset() - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // test - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - _, err := reconciler.Reconcile(req) - assert.NoError(t, err) - - // verify - list, err := clients.Monitoring.MonitoringV1().ServiceMonitors(instance.Namespace).List(context.Background(), metav1.ListOptions{}) - require.NoError(t, err) - - // we assert the correctness of the service in another test - assert.Len(t, list.Items, 1) - - // we assert the correctness of the reference in another test - for _, item := range list.Items { - assert.Len(t, item.OwnerReferences, 1) - } -} - -func TestUpdateServiceMonitor(t *testing.T) { - // prepare - viper.Set(opentelemetry.SvcMonitorAvailable, true) - defer viper.Reset() - - c := serviceMonitor(ctx) - c.Annotations = nil - c.Labels = nil - c.Namespace = instance.Namespace - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(c), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - _, err := clients.Monitoring.MonitoringV1().ServiceMonitors(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - - // test - assert.NoError(t, reconciler.reconcileServiceMonitor(ctx)) - - // verify - _, err = clients.Monitoring.MonitoringV1().ServiceMonitors(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) -} - -func TestDeleteExtraServiceMonitor(t *testing.T) { - // prepare - viper.Set(opentelemetry.SvcMonitorAvailable, true) - defer viper.Reset() - - c := serviceMonitor(ctx) - c.Name = "extra-service" - c.Namespace = instance.Namespace - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(c), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - - // sanity check - _, err := clients.Monitoring.MonitoringV1().ServiceMonitors(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.NoError(t, err) - - // test - assert.NoError(t, reconciler.reconcileServiceMonitor(ctx)) - - // verify - persisted, err := clients.Monitoring.MonitoringV1().ServiceMonitors(c.Namespace).Get(context.Background(), c.Name, metav1.GetOptions{}) - assert.Nil(t, persisted) - assert.Error(t, err) // not found -} diff --git a/pkg/controller/opentelemetrycollector/reconcile_test.go b/pkg/controller/opentelemetrycollector/reconcile_test.go deleted file mode 100644 index 46683f7907..0000000000 --- a/pkg/controller/opentelemetrycollector/reconcile_test.go +++ /dev/null @@ -1,186 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "errors" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/go-logr/logr" - "github.com/stretchr/testify/assert" - appsv1 "k8s.io/api/apps/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/fake" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -func TestProperReconcile(t *testing.T) { - // prepare - var ( - reconciled *v1alpha1.OpenTelemetryCollector - logger logr.Logger - req reconcile.Request - ) - - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req.Namespace = instance.Namespace - req.Name = instance.Name - - called := false - reconciler.reconcileFuncs = []func(context.Context) error{ - func(ctx context.Context) error { - called = true - reconciled = ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger = ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - return nil - }, - } - - // test - res, err := reconciler.Reconcile(req) - - // verify - assert.NoError(t, err) - assert.False(t, res.Requeue) - assert.True(t, called) - assert.Equal(t, instance.Name, reconciled.Name) - assert.NotNil(t, logger) -} - -func TestReconcileDeletedObject(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(), - } - reconciler := New(schem, clients) - - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace}} - reconciler.reconcileFuncs = []func(context.Context) error{ - func(context.Context) error { - assert.Fail(t, "shouldn't have been called") - return nil - }, - } - - // test - res, err := reconciler.Reconcile(req) - - // verify - assert.False(t, res.Requeue) - assert.NoError(t, err) - -} - -func TestReconcileFailsFast(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - req := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: instance.Namespace, Name: instance.Name}} - reconciler.reconcileFuncs = []func(context.Context) error{ - func(context.Context) error { - return errors.New("the server made a boo boo") - }, - func(context.Context) error { - assert.Fail(t, "shouldn't have been called") - return nil - }, - } - - // test - _, err := reconciler.Reconcile(req) - - // verify - assert.Error(t, err) -} - -func TestReconcileFuncsAreCalled(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(), - } - reconciler := New(schem, clients) - called := false - reconciler.reconcileFuncs = []func(context.Context) error{ - func(context.Context) error { - called = true - return nil - }, - } - - // test - err := reconciler.handleReconcile(ctx) - - // verify - assert.NoError(t, err) - assert.True(t, called) -} - -func TestNilReconcileFuncs(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(), - } - reconciler := New(schem, clients) - reconciler.reconcileFuncs = nil - - // test - err := reconciler.handleReconcile(ctx) - - // verify - assert.NoError(t, err) -} - -func TestSetControllerReference(t *testing.T) { - // prepare - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(instance), - } - reconciler := New(schem, clients) - d := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{ - Namespace: instance.Namespace, - }} - - // sanity check - assert.Len(t, d.OwnerReferences, 0) - - // test - err := reconciler.setControllerReference(ctx, d) - assert.NoError(t, err) - - // verify - assert.Len(t, d.OwnerReferences, 1) - assert.Equal(t, instance.Name, d.OwnerReferences[0].Name) - assert.Equal(t, instance.TypeMeta.APIVersion, d.OwnerReferences[0].APIVersion) - assert.Equal(t, instance.TypeMeta.Kind, d.OwnerReferences[0].Kind) - -} - -func TestNameGeneration(t *testing.T) { - instanceName := "test" - expectedResourceName := "test-collector" - - assert.Equal(t, expectedResourceName, resourceName(instanceName)) -} diff --git a/pkg/controller/opentelemetrycollector/upgrade.go b/pkg/controller/opentelemetrycollector/upgrade.go deleted file mode 100644 index 840c57f76b..0000000000 --- a/pkg/controller/opentelemetrycollector/upgrade.go +++ /dev/null @@ -1,43 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - - "github.com/go-logr/logr" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/upgrade" - "github.com/open-telemetry/opentelemetry-operator/pkg/version" -) - -func (r *ReconcileOpenTelemetryCollector) applyUpgrades(ctx context.Context) error { - otelcol := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector) - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - - currentVersions := version.Get() - - upgraded := false - if len(otelcol.Status.Version) > 0 { - if otelcol.Status.Version != currentVersions.OpenTelemetryCollector { - // in theory, the version from the Status could be higher than currentVersions.Jaeger, but we let the upgrade routine - // check/handle it - u, err := upgrade.ManagedInstance(ctx, r.clientset, otelcol) - if err != nil { - return err - } - otelcol = u - upgraded = true - } - } - - // at this point, the Jaeger we are managing is in sync with the Operator's version - // if this is a new object, no upgrade was made, so, we just set the version - otelcol.Status.Version = version.Get().OpenTelemetryCollector - - if upgraded { - logger.V(2).Info("managed instance upgraded", "version", otelcol.Status.Version) - } - - return nil -} diff --git a/pkg/controller/opentelemetrycollector/upgrade_test.go b/pkg/controller/opentelemetrycollector/upgrade_test.go deleted file mode 100644 index 01dbe53ceb..0000000000 --- a/pkg/controller/opentelemetrycollector/upgrade_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package opentelemetrycollector - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/stretchr/testify/assert" - "k8s.io/client-go/kubernetes/fake" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" - "github.com/open-telemetry/opentelemetry-operator/pkg/version" -) - -func TestApplyUpgrades(t *testing.T) { - // prepare - instance := &v1alpha1.OpenTelemetryCollector{ - Status: v1alpha1.OpenTelemetryCollectorStatus{ - Version: "0.0.1", - }, - } - ctx := context.WithValue(context.Background(), opentelemetry.ContextInstance, instance) - ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests")) - clients := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(), - } - reconciler := New(schem, clients) - - // test - err := reconciler.applyUpgrades(ctx) - - // verify - assert.NoError(t, err) - assert.NotEqual(t, "0.0.1", instance.Status.Version) - assert.Equal(t, version.Get().OpenTelemetryCollector, instance.Status.Version) -} diff --git a/pkg/parser/receiver_generic_test.go b/pkg/parser/receiver_generic_test.go deleted file mode 100644 index 1d4e88e290..0000000000 --- a/pkg/parser/receiver_generic_test.go +++ /dev/null @@ -1,95 +0,0 @@ -package parser - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGenericReceiverWithEndpoint(t *testing.T) { - builder := NewGenericReceiverParser("myreceiver", map[interface{}]interface{}{ - "endpoint": "0.0.0.0:1234", - }) - - // test - ports, err := builder.Ports(ctxWithLogger) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 1) - assert.Equal(t, int32(1234), ports[0].Port) -} - -func TestGenericReceiverWithInvalidEndpoint(t *testing.T) { - // there's no parser regitered to handle "myreceiver", so, it falls back to the generic parser - builder := NewGenericReceiverParser("myreceiver", map[interface{}]interface{}{ - "endpoint": "0.0.0.0", - }) - - // test - ports, err := builder.Ports(ctxWithLogger) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 0) -} - -func TestDownstreamParsers(t *testing.T) { - for _, tt := range []struct { - receiverName string - parserName string - parserDefaultPort int32 - builder func(string, map[interface{}]interface{}) ReceiverParser - }{ - {"zipkin", parserNameZipkin, 9411, NewZipkinReceiverParser}, - {"opencensus", parserNameOpenCensus, 55678, NewOpenCensusReceiverParser}, - {"otlp", parserNameOTLP, 55680, NewOTLPReceiverParser}, - - // contrib receivers - {"carbon", parserNameCarbon, 2003, NewCarbonReceiverParser}, - {"collectd", parserNameCollectd, 8081, NewCollectdReceiverParser}, - {"sapm", parserNameSAPM, 7276, NewSAPMReceiverParser}, - {"signalfx", parserNameSignalFx, 9943, NewSignalFxReceiverParser}, - {"wavefront", parserNameWavefront, 2003, NewWavefrontReceiverParser}, - {"zipkin-scribe", parserNameZipkinScribe, 9410, NewZipkinScribeReceiverParser}, - } { - - t.Run("Builder", func(t *testing.T) { - // test - builder := tt.builder(tt.receiverName, map[interface{}]interface{}{}) - - // verify - assert.Equal(t, tt.parserName, builder.ParserName()) - }) - - t.Run("DefaultPort", func(t *testing.T) { - // prepare - builder := tt.builder(tt.receiverName, map[interface{}]interface{}{}) - - // test - ports, err := builder.Ports(ctxWithLogger) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 1) - assert.EqualValues(t, tt.parserDefaultPort, ports[0].Port) - assert.Equal(t, tt.receiverName, ports[0].Name) - }) - - t.Run("OverridePort", func(t *testing.T) { - // prepare - builder := tt.builder(tt.receiverName, map[interface{}]interface{}{ - "endpoint": "0.0.0.0:65535", - }) - - // test - ports, err := builder.Ports(ctxWithLogger) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 1) - assert.EqualValues(t, 65535, ports[0].Port) - assert.Equal(t, tt.receiverName, ports[0].Name) - }) - } -} diff --git a/pkg/parser/receiver_jaeger_test.go b/pkg/parser/receiver_jaeger_test.go deleted file mode 100644 index e75bb3f5ca..0000000000 --- a/pkg/parser/receiver_jaeger_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package parser - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestJaegerParserRegistration(t *testing.T) { - // verify - assert.Contains(t, registry, "jaeger") -} - -func TestJaegerMinimalReceiverConfiguration(t *testing.T) { - builder := NewJaegerReceiverParser("jaeger", map[interface{}]interface{}{ - "protocols": map[interface{}]interface{}{ - "grpc": map[interface{}]interface{}{}, - }, - }) - - // test - ports, err := builder.Ports(ctxWithLogger) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 1) - assert.Equal(t, int32(defaultGRPCPort), ports[0].Port) -} - -func TestJaegerOverrideReceiverProtocolPort(t *testing.T) { - builder := NewJaegerReceiverParser("jaeger", map[interface{}]interface{}{ - "protocols": map[interface{}]interface{}{ - "grpc": map[interface{}]interface{}{ - "endpoint": "0.0.0.0:1234", - }, - }, - }) - - // test - ports, err := builder.Ports(ctxWithLogger) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 1) - assert.Equal(t, int32(1234), ports[0].Port) -} - -func TestJaegerDefaultPorts(t *testing.T) { - builder := NewJaegerReceiverParser("jaeger", map[interface{}]interface{}{ - "protocols": map[interface{}]interface{}{ - "grpc": map[interface{}]interface{}{}, - "thrift_http": map[interface{}]interface{}{}, - "thrift_compact": map[interface{}]interface{}{}, - "thrift_binary": map[interface{}]interface{}{}, - }, - }) - - expectedResults := map[string]struct { - portNumber int32 - seen bool - }{ - "jaeger-grpc": {portNumber: defaultGRPCPort}, - "jaeger-thrift-http": {portNumber: defaultThriftHTTPPort}, - "jaeger-thrift-compact": {portNumber: defaultThriftCompactPort}, - "jaeger-thrift-binary": {portNumber: defaultThriftBinaryPort}, - } - - // test - ports, err := builder.Ports(ctxWithLogger) - - // verify - assert.NoError(t, err) - assert.Len(t, ports, 4) - - for _, port := range ports { - r := expectedResults[port.Name] - r.seen = true - expectedResults[port.Name] = r - } - - for k, v := range expectedResults { - assert.True(t, v.seen, "the port %s wasn't included in the service ports", k) - } -} - -func TestJaegerParserName(t *testing.T) { - // test - p := For("jaeger", map[interface{}]interface{}{}) - - // verify - assert.Equal(t, parserNameJaeger, p.ParserName()) -} diff --git a/pkg/parser/receiver_test.go b/pkg/parser/receiver_test.go deleted file mode 100644 index 7d90a98523..0000000000 --- a/pkg/parser/receiver_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package parser - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - corev1 "k8s.io/api/core/v1" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" -) - -var ( - logger = logf.Log.WithName("unit-tests") - ctxWithLogger = context.WithValue(context.Background(), opentelemetry.ContextLogger, logger) -) - -func TestPortName(t *testing.T) { - for _, tt := range []struct { - candidate string - port int32 - expected string - }{ - { - candidate: "my-receiver", - port: 123, - expected: "my-receiver", - }, - { - candidate: "long-name-long-name-long-name-long-name-long-name-long-name-long-name-long-name", - port: 123, - expected: "port-123", - }, - { - candidate: "my-🦄-receiver", - port: 123, - expected: "port-123", - }, - { - candidate: "-my-receiver", - port: 123, - expected: "port-123", - }, - } { - assert.Equal(t, tt.expected, portName(tt.candidate, tt.port)) - } -} - -func TestReceiverType(t *testing.T) { - for _, tt := range []struct { - name string - expected string - }{ - { - name: "myreceiver", - expected: "myreceiver", - }, - { - name: "myreceiver/custom", - expected: "myreceiver", - }, - } { - // test - typ := receiverType(tt.name) - - // assert - assert.Equal(t, tt.expected, typ) - } -} - -func TestParsePortFromEndpoint(t *testing.T) { - for _, tt := range []struct { - endpoint string - expected int32 - errorExpected bool - }{ - // prepare - {"http://localhost:1234", 1234, false}, - {"0.0.0.0:1234", 1234, false}, - {":1234", 1234, false}, - {"no-port", 0, true}, - } { - - // test - val, err := portFromEndpoint(tt.endpoint) - - // verify - if tt.errorExpected { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - - assert.Equal(t, tt.expected, val, "wrong port from endpoint %s: %d", tt.endpoint, val) - } -} - -func TestEndpointInConfigurationIsntString(t *testing.T) { - // prepare - config := map[interface{}]interface{}{ - "endpoint": 123, - } - - // test - p := singlePortFromConfigEndpoint(ctxWithLogger, "myreceiver", config) - - // verify - assert.Nil(t, p) -} - -func TestRetrieveGenericParser(t *testing.T) { - // test - parser := For("myreceiver", map[interface{}]interface{}{}) - - // verify - assert.Equal(t, parserNameGeneric, parser.ParserName()) -} - -func TestRetrieveParserFor(t *testing.T) { - // prepare - builderCalled := false - Register("mock", func(name string, config map[interface{}]interface{}) ReceiverParser { - builderCalled = true - return &mockParser{} - }) - - // test - For("mock", map[interface{}]interface{}{}) - - // verify - assert.True(t, builderCalled) -} - -type mockParser struct { - portsFunc func(context.Context) ([]corev1.ServicePort, error) -} - -func (m *mockParser) Ports(context.Context) ([]corev1.ServicePort, error) { - return nil, nil -} - -func (m *mockParser) ParserName() string { - return "__mock" -} diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go deleted file mode 100644 index 4a2b87315e..0000000000 --- a/pkg/upgrade/upgrade.go +++ /dev/null @@ -1,72 +0,0 @@ -package upgrade - -import ( - "context" - "fmt" - "reflect" - - "github.com/go-logr/logr" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" -) - -// ManagedInstances finds all the otelcol instances for the current operator and upgrades them, if necessary -func ManagedInstances(ctx context.Context, c *client.Clientset) error { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - logger.Info("looking for managed instances to upgrade") - - list, err := c.OpenTelemetry.OpentelemetryV1alpha1().OpenTelemetryCollectors("").List(ctx, metav1.ListOptions{}) - if err != nil { - return fmt.Errorf("failed to get list of otelcol instances: %v", err) - } - - for _, j := range list.Items { - otelcol, err := ManagedInstance(ctx, c, &j) - if err != nil { - // nothing to do at this level, just go to the next instance - continue - } - - if !reflect.DeepEqual(otelcol, j) { - // the CR has changed, store it! - otelcol, err = c.OpenTelemetry.OpentelemetryV1alpha1().OpenTelemetryCollectors(otelcol.Namespace).Update(ctx, otelcol, metav1.UpdateOptions{}) - if err != nil { - logger.Error(err, "failed to store the upgraded otelcol instances", "name", otelcol.Name, "namespace", otelcol.Namespace) - return err - } - - logger.Info("instance upgraded", "name", otelcol.Name, "namespace", otelcol.Namespace) - } - } - - if len(list.Items) == 0 { - logger.Info("no instances to upgrade") - } - - return nil -} - -// ManagedInstance performs the necessary changes to bring the given otelcol instance to the current version -func ManagedInstance(ctx context.Context, cl *client.Clientset, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) { - logger := ctx.Value(opentelemetry.ContextLogger).(logr.Logger) - - if v, ok := versions[otelcol.Status.Version]; ok { - // we don't need to run the upgrade function for the version 'v', only the next ones - for n := v.next; n != nil; n = n.next { - // performs the upgrade to version 'n' - upgraded, err := n.upgrade(cl, otelcol) - if err != nil { - logger.Error(err, "failed to upgrade managed otelcol instances", "name", otelcol.Name, "namespace", otelcol.Namespace) - return otelcol, err - } - - upgraded.Status.Version = n.v - otelcol = upgraded - } - } - - return otelcol, nil -} diff --git a/pkg/upgrade/upgrade_test.go b/pkg/upgrade/upgrade_test.go deleted file mode 100644 index 334a100460..0000000000 --- a/pkg/upgrade/upgrade_test.go +++ /dev/null @@ -1,84 +0,0 @@ -package upgrade - -import ( - "context" - "testing" - - fakemon "github.com/coreos/prometheus-operator/pkg/client/versioned/fake" - "github.com/stretchr/testify/assert" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/kubernetes/fake" - "k8s.io/client-go/kubernetes/scheme" - logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" - - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry" - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" - fakeotclient "github.com/open-telemetry/opentelemetry-operator/pkg/client/versioned/fake" -) - -func TestVersionUpgradeToLatest(t *testing.T) { - // prepare - ctx := context.WithValue(context.Background(), opentelemetry.ContextLogger, logf.Log) - - nsn := types.NamespacedName{Name: "my-instance"} - existing := &v1alpha1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: nsn.Name, - Namespace: nsn.Namespace, - }, - } - existing.Status.Version = "0.0.1" // this is the first version we have an upgrade function - - s := scheme.Scheme - s.AddKnownTypes(v1alpha1.SchemeGroupVersion, - &v1alpha1.OpenTelemetryCollector{}, - &v1alpha1.OpenTelemetryCollectorList{}, - ) - cl := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(existing), - } - - // test - assert.NoError(t, ManagedInstances(ctx, cl)) - - // verify - persisted, err := cl.OpenTelemetry.OpentelemetryV1alpha1().OpenTelemetryCollectors("").Get(context.Background(), nsn.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Equal(t, latest.v, persisted.Status.Version) -} - -func TestUnknownVersion(t *testing.T) { - // prepare - ctx := context.WithValue(context.Background(), opentelemetry.ContextLogger, logf.Log) - nsn := types.NamespacedName{Name: "my-instance"} - existing := &v1alpha1.OpenTelemetryCollector{ - ObjectMeta: metav1.ObjectMeta{ - Name: nsn.Name, - Namespace: nsn.Namespace, - }, - } - existing.Status.Version = "0.0.0" // we don't know how to upgrade from 0.0.0 - - s := scheme.Scheme - s.AddKnownTypes(v1alpha1.SchemeGroupVersion, - &v1alpha1.OpenTelemetryCollector{}, - &v1alpha1.OpenTelemetryCollectorList{}, - ) - cl := &client.Clientset{ - Kubernetes: fake.NewSimpleClientset(), - Monitoring: fakemon.NewSimpleClientset(), - OpenTelemetry: fakeotclient.NewSimpleClientset(existing), - } - - // test - assert.NoError(t, ManagedInstances(ctx, cl)) - - // verify - persisted, err := cl.OpenTelemetry.OpentelemetryV1alpha1().OpenTelemetryCollectors("").Get(context.Background(), nsn.Name, metav1.GetOptions{}) - assert.NoError(t, err) - assert.Equal(t, "0.0.0", persisted.Status.Version) -} diff --git a/pkg/upgrade/v0_2_0.go b/pkg/upgrade/v0_2_0.go deleted file mode 100644 index d815490de5..0000000000 --- a/pkg/upgrade/v0_2_0.go +++ /dev/null @@ -1,12 +0,0 @@ -package upgrade - -import ( - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" -) - -func upgrade0_2_0(cl *client.Clientset, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) { - // this has the same content as `noop`, but it's added a separate function - // to serve as template for versions with an actual upgrade procedure - return otelcol, nil -} diff --git a/pkg/upgrade/versions.go b/pkg/upgrade/versions.go deleted file mode 100644 index f694a88fa3..0000000000 --- a/pkg/upgrade/versions.go +++ /dev/null @@ -1,30 +0,0 @@ -package upgrade - -import ( - "github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1" - "github.com/open-telemetry/opentelemetry-operator/pkg/client" -) - -type version struct { - v string - upgrade func(cl *client.Clientset, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) - next *version -} - -var ( - v0_0_1 = version{v: "0.0.1", upgrade: noop, next: &v0_0_2} - v0_0_2 = version{v: "0.0.2", upgrade: noop, next: &v0_2_0} - v0_2_0 = version{v: "0.2.0", upgrade: upgrade0_2_0} - - latest = &v0_2_0 - - versions = map[string]version{ - v0_0_1.v: v0_0_1, - v0_0_2.v: v0_0_2, - v0_2_0.v: v0_2_0, - } -) - -func noop(cl *client.Clientset, otelcol *v1alpha1.OpenTelemetryCollector) (*v1alpha1.OpenTelemetryCollector, error) { - return otelcol, nil -} diff --git a/pkg/version/main_test.go b/pkg/version/main_test.go deleted file mode 100644 index fdd6a8c866..0000000000 --- a/pkg/version/main_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package version - -import ( - "testing" - - "gotest.tools/assert" -) - -func TestDefaultOpenTelemetryCollector(t *testing.T) { - assert.Equal(t, "0.0.0", DefaultOpenTelemetryCollector()) -} - -func TestCurrentOpenTelemetryCollector(t *testing.T) { - otelCol = "0.0.2" // set during the build - defer func() { - otelCol = "" - }() - assert.Equal(t, "0.0.2", Get().OpenTelemetryCollector) -} diff --git a/tools.go b/tools.go deleted file mode 100644 index 52a9fac4e0..0000000000 --- a/tools.go +++ /dev/null @@ -1,3 +0,0 @@ -// +build tools - -package tools diff --git a/opentelemetry.version b/versions.txt similarity index 100% rename from opentelemetry.version rename to versions.txt