Compare commits

...

30 Commits

Author SHA1 Message Date
Anoop Gopalakrishnan c0557127de
Merge pull request #396 from roguepikachu/chore/upgrade-go-k8s-version
Chore: upgrades Go (1.23.8) and K8s (1.31.0) versions
2025-07-07 10:12:58 +05:30
Ayush 2e7d7be21b test: improve error messages and assertions in configuration tests
Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
2025-07-04 09:09:30 +05:30
Ayush 599f5b83b4 refactor: update provider package references and enhance fake client setup in tests
Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
2025-07-03 12:56:28 +05:30
Ayush d68a2bc207 fix: update test cases and error messages for better clarity
Signed-off-by: Ayush <ayushshyamkumar888@gmail.com>
2025-07-03 12:56:28 +05:30
Pushparaj Shetty K S ee52ee1f10 update terraform crds
Signed-off-by: Pushparaj Shetty K S <pshettyks@guidewire.com>
2025-06-30 10:20:11 +05:30
Pushparaj Shetty K S 708116dca3 update makefile
Signed-off-by: Pushparaj Shetty K S <pshettyks@guidewire.com>
2025-06-30 10:20:11 +05:30
Pushparaj Shetty K S c602f9ba6b update unit test
Signed-off-by: Pushparaj Shetty K S <pshettyks@guidewire.com>
2025-06-30 10:20:11 +05:30
Pushparaj Shetty K S fe39f2314c update makefile
Signed-off-by: Pushparaj Shetty K S <pshettyks@guidewire.com>
2025-06-30 10:20:11 +05:30
Pushparaj Shetty K S 56411056ed update lint and some dependency version
Signed-off-by: Pushparaj Shetty K S <pshettyks@guidewire.com>
2025-06-30 10:20:11 +05:30
Pushparaj Shetty K S d2f5598bd2 update ubuntu version and fix some dependency issue
Signed-off-by: Pushparaj Shetty K S <pshettyks@guidewire.com>
2025-06-30 10:20:11 +05:30
Pushparaj Shetty K S 5618fc875f -supdate the go and k8s version
Signed-off-by: Pushparaj Shetty K S <pshettyks@guidewire.com>
2025-06-30 10:20:11 +05:30
Zheng Xi Zhou 0845592ef1
Update the link of kubevela project (#386)
As the project of KubeVela was moved from `oam` to `kubevela` space, updated the link for it.
2024-03-12 21:10:54 +08:00
qiaozp 966471af19
Refactor constructing containers and support checkout certain git refs (#382) 2023-09-25 14:25:36 +08:00
zhangsiwei 3536da5d3d
Fix: Keep the backend secret when clean up SubResources if the deleteResou… (#381)
Co-authored-by: zhangsiwei <zhangsiwei@lizhi.fm>
2023-09-22 21:31:21 -05:00
qiaozp eded6d09e8
Refactor: split TFConfigurationMeta to single package (#379) 2023-09-22 11:02:51 +08:00
jaswalkiranavtar 4e21b54765
ISSUE-376: Removing the condition that looks for outputs in tfstate to decide if tfstate is generated or not (#377)
Co-authored-by: Gaurav Jaswal <gjaswal@guidewire.com>
2023-09-01 14:09:31 +08:00
Anoop Gopalakrishnan 1dfb4a3ec8
Fix: replacing tags of busybox and alpine (#370)
- fixes issue #369

Signed-off-by: Anoop Gopalakrishnan <agopalakrishnan@guidewire.com>
Co-authored-by: Lin Ling <lling@guidewire.com>
2023-07-26 11:12:54 +08:00
Somefive b69b78a585
Fix: backup and restore is blocking release, pend it (#368) 2023-06-27 10:10:07 +08:00
Somefive 87fb0fe348
Fix: update chart release (#367) 2023-06-21 14:29:36 +08:00
xingming01 3afed4a627
Fix: reconcile after configuration's hcl changed (#360)
Co-authored-by: caoxingming <caoxingming@jd.com>
2023-06-08 10:23:34 +08:00
吴就业 d2e6f21b29
fix: The execution of the terraformDestroy method fails and the appli… (#366)
Co-authored-by: 吴就业 <wujiuye@lizhi.fm>
2023-06-01 14:00:59 +08:00
吴就业 a8a6504ded
fix: Check whether the namespace of Secret and ConfigMap is the same … (#365)
Co-authored-by: 吴就业 <wujiuye@lizhi.fm>
2023-05-30 10:00:59 +08:00
吴就业 6e51e97210
feat: Supports marking a job as failed after specifying a few retries… (#362)
* feat: Supports marking a job as failed after specifying a few retries #361

Signed-off-by: 吴就业 <wujiuye@lizhi.fm>

* Values.jobBackoffLimit defaults to ""

Signed-off-by: 吴就业 <wujiuye@lizhi.fm>

---------

Signed-off-by: 吴就业 <wujiuye@lizhi.fm>
Co-authored-by: 吴就业 <wujiuye@lizhi.fm>
2023-05-19 17:50:07 +08:00
qiaozp f8184ed615
Bump docker-terraform image to 1.1.5 (#356)
Signed-off-by: Qiaozp <qiaozhongpei.qzp@alibaba-inc.com>
2023-02-12 21:43:16 +08:00
qiaozp e2f31a4b6b
Feat: allow delete the provisioning resources (#354)
* Feat: allow delete configuration halfway the apply

* Modify chart

* Add test

Fix test script

* smaller quota

Signed-off-by: Qiaozp <qiaozhongpei.qzp@alibaba-inc.com>

---------

Signed-off-by: Qiaozp <qiaozhongpei.qzp@alibaba-inc.com>
2023-02-09 14:03:50 +08:00
qiaozp 58fad4c416
Revert "feat: add libc6-compat to fix dynamic linking issue, add ca-certificates" (#355)
This reverts commit 7a102d31a6.

Signed-off-by: Qiaozp <qiaozhongpei.qzp@alibaba-inc.com>
2023-02-09 13:49:36 +08:00
Ramesh Krishna 7a102d31a6
feat: add libc6-compat to fix dynamic linking issue, add ca-certificates (#353)
Signed-off-by: raradhakrishnan <raradhakrishnan@guidewire.com>
2023-02-07 10:03:13 +08:00
Ramesh Krishna c6d69a8828
Feat: support private terraform registry (#352)
Co-authored-by: qiaozp <47812250+chivalryq@users.noreply.github.com>
2023-01-19 11:36:33 +08:00
Joshua Agboola 841b0d17d9
Feat: Support retrieving modules in private git repo through SSH (#349) 2022-12-09 10:31:30 +08:00
Nan Li 55fd92efa4
Fix the build error of the Release action (#344) 2022-08-23 11:21:24 +08:00
66 changed files with 5469 additions and 3386 deletions

View File

@ -1,109 +0,0 @@
name: Chart
on:
push:
branches:
- master
tags:
- "v*"
workflow_dispatch: {}
env:
BUCKET: kubevelacharts
ENDPOINT: oss-cn-hangzhou.aliyuncs.com
ACCESS_KEY: ${{ secrets.OSS_ACCESS_KEY }}
ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
HELM_CHART: chart
LOCAL_OSS_DIRECTORY: .oss/
jobs:
chart-build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@master
- name: Get the version
id: get_version
run: |
tag=${GITHUB_REF#refs/tags/}
VERSION=${tag#"v"}
if [[ ${GITHUB_REF} == "refs/heads/master" ]]; then
VERSION=latest
fi
echo ::set-output name=VERSION::${VERSION}
- name: Get git revision
id: vars
shell: bash
run: |
echo "::set-output name=git_revision::$(git rev-parse --short HEAD)"
- name: Login docker.io
uses: docker/login-action@v1
with:
registry: docker.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: docker/setup-qemu-action@v1
- uses: docker/setup-buildx-action@v1
with:
driver-opts: image=moby/buildkit:master
- uses: docker/build-push-action@v2
name: Build & Pushing terraform controller for Dockerhub
with:
context: .
file: Dockerfile
labels: |-
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.revision=${{ github.sha }}
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
build-args: |
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
VERSION=${{ steps.get_version.outputs.VERSION }}
GOPROXY=https://proxy.golang.org
tags: |-
docker.io/oamdev/terraform-controller:${{ steps.get_version.outputs.VERSION }}
- name: Install Helm
uses: azure/setup-helm@v1
with:
version: v3.4.0
- uses: oprypin/find-latest-tag@v1
with:
repository: oam-dev/terraform-controller
releases-only: true
id: latest_tag
- name: Tag helm chart image
run: |
latest_repo_tag=${{ steps.latest_tag.outputs.tag }}
sub="."
major="$(cut -d"$sub" -f1 <<<"$latest_repo_tag")"
minor="$(cut -d"$sub" -f2 <<<"$latest_repo_tag")"
patch="0"
current_repo_tag="$major.$minor.$patch"
tag=${GITHUB_REF#refs/tags/}
image_tag=${tag#"v"}
chart_version=$latest_repo_tag
if [[ ${GITHUB_REF} == "refs/heads/master" ]]; then
image_tag=latest
chart_version=${current_repo_tag}-nightly-build
fi
# sed -i "s/0.2.8/${image_tag}/g" $HELM_CHART/Makefile
chart_smever=${chart_version#"v"}
sed -i "s/0.2.8/$chart_smever/g" $HELM_CHART/Chart.yaml
sed -i "s/0.2.8/${image_tag}/g" $HELM_CHART/values.yaml
- name: Install ossutil
run: wget http://gosspublic.alicdn.com/ossutil/1.7.0/ossutil64 && chmod +x ossutil64 && mv ossutil64 ossutil
- name: Configure Alibaba Cloud OSSUTIL
run: ./ossutil --config-file .ossutilconfig config -i ${ACCESS_KEY} -k ${ACCESS_KEY_SECRET} -e ${ENDPOINT} -c .ossutilconfig
- name: sync cloud to local
run: ./ossutil --config-file .ossutilconfig cp oss://$BUCKET/addons/index.yaml $LOCAL_OSS_DIRECTORY -f
- name: Package helm charts
run: |
helm package $HELM_CHART --destination $LOCAL_OSS_DIRECTORY
helm repo index --url https://charts.kubevela.net/addons $LOCAL_OSS_DIRECTORY/ --merge $LOCAL_OSS_DIRECTORY/index.yaml
- name: sync local to cloud
run: ./ossutil --config-file .ossutilconfig sync $LOCAL_OSS_DIRECTORY oss://$BUCKET/addons -f

54
.github/workflows/build-image.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: BuildImage
on:
push:
tags:
- 'v*'
workflow_dispatch: { }
jobs:
build-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
oamdev/terraform-controller
ghcr.io/kubevela/oamdev/terraform-controller
tags: |
type=ref,event=tag
type=raw,value=latest,enable={{is_default_branch}}
- name: Login docker.io
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0
with:
registry: docker.io
username: ${{ secrets.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

48
.github/workflows/chart.yml vendored Normal file
View File

@ -0,0 +1,48 @@
name: HelmChart
on:
push:
tags:
- "v*"
workflow_dispatch: {}
jobs:
publish-charts:
env:
HELM_CHART: chart/
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Install Helm
uses: azure/setup-helm@v1
with:
version: v3.4.0
- name: Get the version
id: get_version
run: |
VERSION=${GITHUB_REF#refs/tags/}
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
- name: Tag helm chart image
run: |
image_tag=${{ steps.get_version.outputs.VERSION }}
chart_version=${{ steps.get_version.outputs.VERSION }}
sed -i "s/tag: latest/tag: ${image_tag}/g" $HELM_CHART/values.yaml
chart_semver=${chart_version#"v"}
sed -i "s/0.1.0/$chart_semver/g" $HELM_CHART/Chart.yaml
- uses: jnwng/github-app-installation-token-action@v2
id: get_app_token
with:
appId: 340472
installationId: 38064967
privateKey: ${{ secrets.GH_KUBEVELA_APP_PRIVATE_KEY }}
- name: Sync Chart Repo
run: |
git config --global user.email "135009839+kubevela[bot]@users.noreply.github.com"
git config --global user.name "kubevela[bot]"
git clone https://x-access-token:${{ steps.get_app_token.outputs.token }}@github.com/kubevela/charts.git kubevela-charts
helm package $HELM_CHART --destination ./kubevela-charts/docs/
helm repo index --url https://kubevela.github.io/charts ./kubevela-charts/docs/
cd kubevela-charts/
git add docs/
chart_version=${GITHUB_REF#refs/tags/}
git commit -m "update terraform-controller chart ${chart_version}"
git push https://x-access-token:${{ steps.get_app_token.outputs.token }}@github.com/kubevela/charts.git

View File

@ -12,12 +12,12 @@ on:
- master
env:
GO_VERSION: '1.17.6'
GO_VERSION: '1.23.8'
KIND_VERSION: 'v0.12.0'
jobs:
e2e-tests:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Check out code into the Go module directory
@ -52,7 +52,7 @@ jobs:
run: |
kubectl cluster-info
echo "current-context:" $(kubectl config current-context)
helm upgrade --install --create-namespace --namespace terraform terraform-controller ./chart --set image.tag=e2e --set image.pullPolicy=IfNotPresent --set backend.namespace=terraform
helm upgrade --install --create-namespace --namespace terraform terraform-controller ./chart --set image.tag=e2e --set image.pullPolicy=IfNotPresent --set backend.namespace=terraform --wait
helm test -n terraform terraform-controller --timeout 5m
kubectl get pod -n terraform -l "app=terraform-controller"

View File

@ -13,12 +13,12 @@ on:
env:
# Common versions
GO_VERSION: '1.17.6'
GO_VERSION: '1.23.8'
KIND_VERSION: 'v0.7.0'
jobs:
detect-noop:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
outputs:
noop: ${{ steps.noop.outputs.should_skip }}
steps:
@ -32,7 +32,7 @@ jobs:
concurrent_skipping: false
make-reviewable:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: detect-noop
if: needs.detect-noop.outputs.noop != 'true'

View File

@ -1,9 +1,6 @@
name: Release
on:
push:
tags:
- "v*"
workflow_dispatch: { }
env:
@ -19,7 +16,7 @@ jobs:
env:
BACKUP_RESTORE_TOOL_VERSION_KEY: github.com/kubevela/terraform-controller/version.BackupRestoreToolVersion
BACKUP_RESTORE_TOOL_VERSION: cat hack/tool/backup_restore/VERSION
GO_BUILD_ENV: GO111MODULE=on CGO_ENABLED=0
GO_BUILD_ENV: GO111MODULE=on
DIST_DIRS: find * -type d -exec
steps:
- name: Checkout
@ -27,7 +24,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: 1.23
- name: Get release
id: get_release
uses: bruceadams/get-release@v1.2.2
@ -44,10 +41,11 @@ jobs:
echo "LDFLAGS=${LDFLAGS}" >> $GITHUB_ENV
- name: Build
run: |
cd ./hack/tool/backup_restore && \
${{ env.GO_BUILD_ENV }} GOOS=${{ steps.get_matrix.outputs.OS }} GOARCH=${{ steps.get_matrix.outputs.ARCH }} \
go build -ldflags "${{ env.LDFLAGS }}" \
-o _bin/backup_restore/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}/backup_restore -v \
./hack/tool/backup_restore/main.go
go build -ldflags "${{ env.LDFLAGS }}" \
-o _bin/backup_restore/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}/backup_restore \
-v .
- name: Compress
run: |
cd _bin/backup_restore && \

View File

@ -15,7 +15,7 @@ on:
env:
# Common versions
GO_VERSION: '1.17.6'
GO_VERSION: '1.23.8'
jobs:
lint:
@ -31,7 +31,7 @@ jobs:
make lint
unit-tests:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- name: Set up Go
@ -46,7 +46,7 @@ jobs:
submodules: true
- name: Cache Go Dependencies
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: .work/pkg
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}

3
.gitignore vendored
View File

@ -30,3 +30,6 @@ terraform-controller-*
examples/tf-native/alibaba/cs/kubeconfig
bin/manager
# Secret for git server
examples/git-credentials/git-ssh-auth-secret.yaml

View File

@ -2,12 +2,11 @@ run:
timeout: 10m
skip-files:
- "zz_generated\\..+\\.go$"
- ".*_test.go$"
output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
format: colored-line-number
formats: colored-line-number
linters-settings:
errcheck:
@ -22,7 +21,7 @@ linters-settings:
# [deprecated] comma-separated list of pairs of the form pkg:regex
# the regex is used to ignore names within pkg. (default "fmt:.*").
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
ignore: fmt:.*,io/ioutil:^Read.*
exclude-functions: fmt:.*,io/ioutil:^Read.*
exhaustive:
# indicates that switch statements are to be considered exhaustive if a
@ -44,7 +43,7 @@ linters-settings:
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 30
min-complexity: 32
maligned:
# print struct with more effective memory layout or not, false by default
@ -100,7 +99,6 @@ linters-settings:
linters:
enable:
- megacheck
- govet
- gocyclo
- gocritic
@ -111,6 +109,9 @@ linters:
- unconvert
- misspell
- nakedret
- staticcheck
- gosimple
- unused
presets:
- bugs
@ -119,6 +120,12 @@ linters:
issues:
exclude-files:
# Exclude files that are generated by controller-gen.
- "zz_generated\\..+\\.go$"
# Exclude test files.
- ".*_test.go$"
# Excluding configuration per-path and per-linter
exclude-rules:
# Exclude some linters from running on tests files.
@ -179,6 +186,14 @@ issues:
linters:
- revive
- text: "package-comments:"
linters:
- revive
- text: "exported:"
linters:
- revive
# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.

View File

@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.17-alpine as builder
FROM golang:1.23-alpine as builder
WORKDIR /workspace
# Copy the Go Modules manifests

View File

@ -3,7 +3,7 @@
IMG ?= oamdev/terraform-controller:0.2.8
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd:trivialVersions=true"
CRD_OPTIONS ?= "crd"
TIME_SHORT = `date +%H:%M:%S`
TIME = $(TIME_SHORT)
@ -82,7 +82,7 @@ ifeq (, $(shell which controller-gen))
CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
cd $$CONTROLLER_GEN_TMP_DIR ;\
go mod init tmp ;\
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.0 ;\
go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.5 ;\
rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
}
CONTROLLER_GEN=$(GOBIN)/controller-gen
@ -90,7 +90,7 @@ else
CONTROLLER_GEN=$(shell which controller-gen)
endif
GOLANGCILINT_VERSION ?= v1.38.0
GOLANGCILINT_VERSION ?= v1.60.1
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]')
HOSTARCH := $(shell uname -m)
ifeq ($(HOSTARCH),x86_64)
@ -131,7 +131,7 @@ goimports:
ifeq (, $(shell which goimports))
@{ \
set -e ;\
GO111MODULE=off go get -u golang.org/x/tools/cmd/goimports ;\
go install golang.org/x/tools/cmd/goimports@latest ;\
}
GOIMPORTS=$(GOBIN)/goimports
else
@ -267,7 +267,7 @@ custom: custom-credentials custom-provider
configuration:
go test -coverprofile=e2e-coverage1.xml -v $(go list ./e2e/...|grep -v controllernamespace) -count=1
go test -coverprofile=e2e-coverage1.xml -v $(shell go list ./e2e/...|grep -v controllernamespace) -count=1
go test -v ./e2e/controllernamespace/...
e2e-setup: install-chart alibaba

77
api/types/const.go Normal file
View File

@ -0,0 +1,77 @@
package types
const (
DefaultNamespace = "default"
GitCredsKnownHosts = "known_hosts"
// TerraformCredentials -
TerraformCredentials = "credentials.tfrc.json"
// TerraformRegistryConfig -
TerraformRegistryConfig = ".terraformrc"
)
const (
// TerraformContainerName is the name of the container that executes terraform in the pod
TerraformContainerName = "terraform-executor"
TerraformInitContainerName = "terraform-init"
)
const (
// TFInputConfigMapName is the CM name for Terraform Input Configuration
TFInputConfigMapName = "tf-%s"
// TFVariableSecret is the Secret name for variables, including credentials from Provider
TFVariableSecret = "variable-%s"
)
// TerraformExecutionType is the type for Terraform execution
type TerraformExecutionType string
const (
// TerraformApply is the name to mark `terraform apply`
TerraformApply TerraformExecutionType = "apply"
// TerraformDestroy is the name to mark `terraform destroy`
TerraformDestroy TerraformExecutionType = "destroy"
)
const (
// ClusterRoleName is the name of the ClusterRole for Terraform Job
ClusterRoleName = "tf-executor-clusterrole"
// ServiceAccountName is the name of the ServiceAccount for Terraform Job
ServiceAccountName = "tf-executor-service-account"
)
// Volume names and mount paths
const (
// WorkingVolumeMountPath is the mount path for working volume
WorkingVolumeMountPath = "/data"
// InputTFConfigurationVolumeName is the volume name for input Terraform Configuration
InputTFConfigurationVolumeName = "tf-input-configuration"
// InputTFConfigurationVolumeMountPath is the volume mount path for input Terraform Configuration
InputTFConfigurationVolumeMountPath = "/opt/tf-configuration"
// BackendVolumeName is the volume name for Terraform backend
BackendVolumeName = "tf-backend"
// BackendVolumeMountPath is the volume mount path for Terraform backend
BackendVolumeMountPath = "/opt/tf-backend"
// GitAuthConfigVolumeName is the volume name for git auth configurtaion
GitAuthConfigVolumeName = "git-auth-configuration"
// GitAuthConfigVolumeMountPath is the volume mount path for git auth configurtaion
GitAuthConfigVolumeMountPath = "/root/.ssh"
// TerraformCredentialsConfigVolumeName is the volume name for terraform auth configurtaion
TerraformCredentialsConfigVolumeName = "terraform-credentials-configuration"
// TerraformCredentialsConfigVolumeMountPath is the volume mount path for terraform auth configurtaion
TerraformCredentialsConfigVolumeMountPath = "/root/.terraform.d"
// TerraformRCConfigVolumeName is the volume name of the terraform registry configuration
TerraformRCConfigVolumeName = "terraform-rc-configuration"
// TerraformRCConfigVolumeMountPath is the volume mount path for registry configuration
TerraformRCConfigVolumeMountPath = "/root"
// TerraformCredentialsHelperConfigVolumeName is the volume name for terraform auth configurtaion
TerraformCredentialsHelperConfigVolumeName = "terraform-credentials-helper-configuration"
// TerraformCredentialsHelperConfigVolumeMountPath is the volume mount path for terraform auth configurtaion
TerraformCredentialsHelperConfigVolumeMountPath = "/root/.terraform.d/plugins"
)

View File

@ -21,27 +21,31 @@ type ConfigurationState string
// Reasons a resource is or is not ready.
const (
Authorizing ConfigurationState = "Authorizing"
ProviderNotFound ConfigurationState = "ProviderNotFound"
ProviderNotReady ConfigurationState = "ProviderNotReady"
ConfigurationStaticCheckFailed ConfigurationState = "ConfigurationSpecNotValid"
Available ConfigurationState = "Available"
ConfigurationProvisioningAndChecking ConfigurationState = "ProvisioningAndChecking"
ConfigurationDestroying ConfigurationState = "Destroying"
ConfigurationApplyFailed ConfigurationState = "ApplyFailed"
ConfigurationDestroyFailed ConfigurationState = "DestroyFailed"
ConfigurationReloading ConfigurationState = "ConfigurationReloading"
GeneratingOutputs ConfigurationState = "GeneratingTerraformOutputs"
InvalidRegion ConfigurationState = "InvalidRegion"
TerraformInitError ConfigurationState = "TerraformInitError"
Authorizing ConfigurationState = "Authorizing"
ProviderNotFound ConfigurationState = "ProviderNotFound"
ProviderNotReady ConfigurationState = "ProviderNotReady"
ConfigurationStaticCheckFailed ConfigurationState = "ConfigurationSpecNotValid"
Available ConfigurationState = "Available"
ConfigurationProvisioningAndChecking ConfigurationState = "ProvisioningAndChecking"
ConfigurationDestroying ConfigurationState = "Destroying"
ConfigurationApplyFailed ConfigurationState = "ApplyFailed"
ConfigurationDestroyFailed ConfigurationState = "DestroyFailed"
ConfigurationReloading ConfigurationState = "ConfigurationReloading"
GeneratingOutputs ConfigurationState = "GeneratingTerraformOutputs"
InvalidRegion ConfigurationState = "InvalidRegion"
TerraformInitError ConfigurationState = "TerraformInitError"
InvalidGitCredentialsSecretReference ConfigurationState = "InvalidGitCredentialsSecretReference"
InvalidTerraformCredentialsSecretReference ConfigurationState = "InvalidTerraformCredentialsSecretReference"
InvalidTerraformRCConfigMapReference ConfigurationState = "InvalidTerraformRCConfigMapReference"
InvalidTerraformCredentialsHelperConfigMapReference ConfigurationState = "InvalidTerraformCredentialsHelperConfigMapReference"
)
// Stage is the Terraform stage
type Stage string
const (
TerraformInit Stage = "TerraformInit"
TerraformApply Stage = "TerraformApply"
InitStage Stage = "InitStage"
ApplyStage Stage = "Apply"
)
const (

View File

@ -1,5 +1,7 @@
package types
import "k8s.io/apimachinery/pkg/api/resource"
const (
// TerraformHCLConfigurationName is the file name for Terraform hcl Configuration
TerraformHCLConfigurationName = "main.tf"
@ -14,3 +16,27 @@ const (
// ConfigurationRemote means HCL stores in a remote git repository
ConfigurationRemote ConfigurationType = "Remote"
)
type Git struct {
URL string
Path string
Ref GitRef
}
// GitRef specifies the git reference
type GitRef struct {
Branch string `json:"branch,omitempty"`
Tag string `json:"tag,omitempty"`
Commit string `json:"commit,omitempty"`
}
type ResourceQuota struct {
ResourcesLimitsCPU string
ResourcesLimitsCPUQuantity resource.Quantity
ResourcesLimitsMemory string
ResourcesLimitsMemoryQuantity resource.Quantity
ResourcesRequestsCPU string
ResourcesRequestsCPUQuantity resource.Quantity
ResourcesRequestsMemory string
ResourcesRequestsMemoryQuantity resource.Quantity
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package v1beta1
import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -47,6 +48,18 @@ type ConfigurationSpec struct {
Path string `json:"path,omitempty"`
BaseConfigurationSpec `json:",inline"`
// GitCredentialsSecretReference specifies the reference to the secret containing the git credentials
GitCredentialsSecretReference *v1.SecretReference `json:"gitCredentialsSecretReference,omitempty"`
// TerraformCredentialsSecretReference specifies the reference to the secret containing the terraform credentials
TerraformCredentialsSecretReference *v1.SecretReference `json:"terraformCredentialsSecretReference,omitempty"`
// TerraformRCConfigMapReference specifies the reference to a config map containing the terraform registry configuration
TerraformRCConfigMapReference *v1.SecretReference `json:"terraformRCConfigMapReference,omitempty"`
// TerraformCredentialsHelperConfigMapReference specifies the reference to a configmap containing the terraform registry credentials helper
TerraformCredentialsHelperConfigMapReference *v1.SecretReference `json:"terraformCredentialsHelperConfigMapReference,omitempty"`
}
// BaseConfigurationSpec defines the common fields of a ConfigurationSpec
@ -113,6 +126,7 @@ type Backend struct {
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="STATE",type="string",JSONPath=".status.apply.state"
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:resource:shortName={conf,terraform-conf}
type Configuration struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

View File

@ -1,5 +1,4 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2021 The KubeVela Authors.
@ -23,6 +22,7 @@ package v1beta1
import (
crossplane_runtime "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
)
@ -176,6 +176,26 @@ func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
**out = **in
}
in.BaseConfigurationSpec.DeepCopyInto(&out.BaseConfigurationSpec)
if in.GitCredentialsSecretReference != nil {
in, out := &in.GitCredentialsSecretReference, &out.GitCredentialsSecretReference
*out = new(v1.SecretReference)
**out = **in
}
if in.TerraformCredentialsSecretReference != nil {
in, out := &in.TerraformCredentialsSecretReference, &out.TerraformCredentialsSecretReference
*out = new(v1.SecretReference)
**out = **in
}
if in.TerraformRCConfigMapReference != nil {
in, out := &in.TerraformRCConfigMapReference, &out.TerraformRCConfigMapReference
*out = new(v1.SecretReference)
**out = **in
}
if in.TerraformCredentialsHelperConfigMapReference != nil {
in, out := &in.TerraformCredentialsHelperConfigMapReference, &out.TerraformCredentialsHelperConfigMapReference
*out = new(v1.SecretReference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec.

View File

@ -17,10 +17,11 @@ limitations under the License.
package v1beta2
import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
state "github.com/oam-dev/terraform-controller/api/types"
apitypes "github.com/oam-dev/terraform-controller/api/types"
types "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
)
@ -32,6 +33,9 @@ type ConfigurationSpec struct {
// Remote is a git repo which contains hcl files. Currently, only public git repos are supported.
Remote string `json:"remote,omitempty"`
// GitRef is the git branch or tag or commit hash to checkout. Only used when Remote is specified.
GitRef apitypes.GitRef `json:"gitRef,omitempty"`
// +kubebuilder:pruning:PreserveUnknownFields
Variable *runtime.RawExtension `json:"variable,omitempty"`
@ -75,6 +79,18 @@ type ConfigurationSpec struct {
// ForceDelete will force delete Configuration no matter which state it is or whether it has provisioned some resources
// It will help delete Configuration in unexpected cases.
ForceDelete *bool `json:"forceDelete,omitempty"`
// GitCredentialsSecretReference specifies the reference to the secret containing the git credentials
GitCredentialsSecretReference *v1.SecretReference `json:"gitCredentialsSecretReference,omitempty"`
// TerraformCredentialsSecretReference specifies the reference to the secret containing the terraform credentials and terraform registry details
TerraformCredentialsSecretReference *v1.SecretReference `json:"terraformCredentialsSecretReference,omitempty"`
// TerraformRCConfigMapReference specifies the reference to a config map containing the terraform registry configuration
TerraformRCConfigMapReference *v1.SecretReference `json:"terraformRCConfigMapReference,omitempty"`
// TerraformCredentialsHelperConfigMapReference specifies the reference to a configmap containing the terraform registry credentials helper
TerraformCredentialsHelperConfigMapReference *v1.SecretReference `json:"terraformCredentialsHelperConfigMapReference,omitempty"`
}
// ConfigurationStatus defines the observed state of Configuration
@ -91,9 +107,9 @@ type ConfigurationStatus struct {
// ConfigurationApplyStatus is the status for Configuration apply
type ConfigurationApplyStatus struct {
State state.ConfigurationState `json:"state,omitempty"`
Message string `json:"message,omitempty"`
Outputs map[string]Property `json:"outputs,omitempty"`
State apitypes.ConfigurationState `json:"state,omitempty"`
Message string `json:"message,omitempty"`
Outputs map[string]Property `json:"outputs,omitempty"`
// Region is the region for the cloud resources created by this Configuration. If spec.region is not empty, it's the
// value of it. Otherwise, it's the value of spec.providerReference.region.
Region string `json:"region,omitempty"`
@ -101,8 +117,8 @@ type ConfigurationApplyStatus struct {
// ConfigurationDestroyStatus is the status for Configuration destroy
type ConfigurationDestroyStatus struct {
State state.ConfigurationState `json:"state,omitempty"`
Message string `json:"message,omitempty"`
State apitypes.ConfigurationState `json:"state,omitempty"`
Message string `json:"message,omitempty"`
}
// Property is the property for an output
@ -150,9 +166,10 @@ type S3BackendConf struct {
// +kubebuilder:object:root=true
// Configuration is the Schema for the configurations API
//+kubebuilder:storageversion
// +kubebuilder:storageversion
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="STATE",type="string",JSONPath=".status.apply.state"
// +kubebuilder:printcolumn:name="APPLY",type="string",JSONPath=".status.apply.state"
// +kubebuilder:printcolumn:name="DESTROY",type="string",JSONPath=".status.destroy.state"
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
type Configuration struct {
metav1.TypeMeta `json:",inline"`

View File

@ -1,5 +1,4 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2021 The KubeVela Authors.
@ -23,6 +22,7 @@ package v1beta2
import (
crossplane_runtime "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
)
@ -150,6 +150,7 @@ func (in *ConfigurationList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
*out = *in
out.GitRef = in.GitRef
if in.Variable != nil {
in, out := &in.Variable, &out.Variable
*out = new(runtime.RawExtension)
@ -170,6 +171,11 @@ func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
*out = new(crossplane_runtime.Reference)
**out = **in
}
if in.JobEnv != nil {
in, out := &in.JobEnv, &out.JobEnv
*out = new(runtime.RawExtension)
(*in).DeepCopyInto(*out)
}
if in.DeleteResource != nil {
in, out := &in.DeleteResource, &out.DeleteResource
*out = new(bool)
@ -180,6 +186,26 @@ func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
*out = new(bool)
**out = **in
}
if in.GitCredentialsSecretReference != nil {
in, out := &in.GitCredentialsSecretReference, &out.GitCredentialsSecretReference
*out = new(v1.SecretReference)
**out = **in
}
if in.TerraformCredentialsSecretReference != nil {
in, out := &in.TerraformCredentialsSecretReference, &out.TerraformCredentialsSecretReference
*out = new(v1.SecretReference)
**out = **in
}
if in.TerraformRCConfigMapReference != nil {
in, out := &in.TerraformRCConfigMapReference, &out.TerraformRCConfigMapReference
*out = new(v1.SecretReference)
**out = **in
}
if in.TerraformCredentialsHelperConfigMapReference != nil {
in, out := &in.TerraformCredentialsHelperConfigMapReference, &out.TerraformCredentialsHelperConfigMapReference
*out = new(v1.SecretReference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec.

View File

@ -1,6 +1,6 @@
apiVersion: v1
name: terraform-controller
version: 0.2.8
version: 0.1.0
description: A Kubernetes Terraform controller
home: https://github.com/oam-dev/terraform-controller
appVersion: "0.3.3"
appVersion: 0.1.0

View File

@ -1,11 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.6.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.16.5
name: configurations.terraform.core.oam.dev
spec:
group: terraform.core.oam.dev
@ -13,6 +11,9 @@ spec:
kind: Configuration
listKind: ConfigurationList
plural: configurations
shortNames:
- conf
- terraform-conf
singular: configuration
scope: Namespaced
versions:
@ -29,14 +30,19 @@ spec:
description: Configuration is the Schema for the configurations 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'
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'
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
@ -44,15 +50,14 @@ spec:
description: ConfigurationSpec defines the desired state of Configuration
properties:
JSON:
description: 'JSON is the Terraform JSON syntax configuration. Deprecated:
after v0.3.1, use HCL instead.'
description: |-
JSON is the Terraform JSON syntax configuration.
Deprecated: after v0.3.1, use HCL instead.
type: string
backend:
description: Backend stores the state in a Kubernetes secret with
locking done using a Lease resource. TODO(zzxwill) If a backend
exists in HCL/JSON, this can be optional. Currently, if Backend
is not set by users, it still will set by the controller, ignoring
the settings in HCL/JSON backend
description: |-
Backend stores the state in a Kubernetes secret with locking done using a Lease resource.
still will set by the controller, ignoring the settings in HCL/JSON backend
properties:
inClusterConfig:
description: InClusterConfig Used to authenticate to the cluster
@ -68,6 +73,20 @@ spec:
description: DeleteResource will determine whether provisioned cloud
resources will be deleted when CR is deleted
type: boolean
gitCredentialsSecretReference:
description: GitCredentialsSecretReference specifies the reference
to the secret containing the git credentials
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
hcl:
description: HCL is the Terraform HCL type configuration
type: string
@ -95,15 +114,58 @@ spec:
description: Remote is a git repo which contains hcl files. Currently,
only public git repos are supported.
type: string
terraformCredentialsHelperConfigMapReference:
description: TerraformCredentialsHelperConfigMapReference specifies
the reference to a configmap containing the terraform registry credentials
helper
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
terraformCredentialsSecretReference:
description: TerraformCredentialsSecretReference specifies the reference
to the secret containing the terraform credentials
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
terraformRCConfigMapReference:
description: TerraformRCConfigMapReference specifies the reference
to a config map containing the terraform registry configuration
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
variable:
type: object
x-kubernetes-preserve-unknown-fields: true
writeConnectionSecretToRef:
description: WriteConnectionSecretToReference specifies the namespace
and name of a Secret to which any connection details for this managed
resource should be written. Connection details frequently include
the endpoint, username, and password required to connect to the
managed resource.
description: |-
WriteConnectionSecretToReference specifies the namespace and name of a
Secret to which any connection details for this managed resource should
be written. Connection details frequently include the endpoint, username,
and password required to connect to the managed resource.
properties:
name:
description: Name of the secret.
@ -149,9 +211,9 @@ spec:
type: string
type: object
observedGeneration:
description: observedGeneration is the most recent generation observed
for this Configuration. It corresponds to the Configuration's generation,
which is updated on mutation by the API Server.
description: |-
observedGeneration is the most recent generation observed for this Configuration. It corresponds to the
Configuration's generation, which is updated on mutation by the API Server.
format: int64
type: integer
type: object
@ -162,7 +224,10 @@ spec:
status: {}
- additionalPrinterColumns:
- jsonPath: .status.apply.state
name: STATE
name: APPLY
type: string
- jsonPath: .status.destroy.state
name: DESTROY
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
@ -173,28 +238,35 @@ spec:
description: Configuration is the Schema for the configurations 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'
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'
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: ConfigurationSpec defines the desired state of Configuration
properties:
JobEnv:
type: object
x-kubernetes-preserve-unknown-fields: true
backend:
description: 'Backend describes the Terraform backend configuration.
This field is needed if the users use a git repo to provide the
hcl files or want to use their custom Terraform backend (instead
of the default kubernetes backend type). Notice: This field may
cause two backend blocks in the final Terraform module and make
the executor job failed. So, please make sure that there are no
backend configurations in your inline hcl code or the git repo.'
description: |-
Backend describes the Terraform backend configuration.
This field is needed if the users use a git repo to provide the hcl files or
want to use their custom Terraform backend (instead of the default kubernetes backend type).
Notice: This field may cause two backend blocks in the final Terraform module and make the executor job failed.
So, please make sure that there are no backend configurations in your inline hcl code or the git repo.
properties:
backendType:
description: BackendType indicates which backend type to use.
@ -252,19 +324,44 @@ spec:
resources will be deleted when CR is deleted
type: boolean
forceDelete:
description: ForceDelete will force delete Configuration no matter
which state it is or whether it has provisioned some resources It
will help delete Configuration in unexpected cases.
description: |-
ForceDelete will force delete Configuration no matter which state it is or whether it has provisioned some resources
It will help delete Configuration in unexpected cases.
type: boolean
gitCredentialsSecretReference:
description: GitCredentialsSecretReference specifies the reference
to the secret containing the git credentials
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
gitRef:
description: GitRef is the git branch or tag or commit hash to checkout.
Only used when Remote is specified.
properties:
branch:
type: string
commit:
type: string
tag:
type: string
type: object
hcl:
description: HCL is the Terraform HCL type configuration
type: string
inlineCredentials:
description: "InlineCredentials specifies the credentials in spec.HCl
field as below. \tprovider \"aws\" { \t\tregion = \"us-west-2\"
\t\taccess_key = \"my-access-key\" \t\tsecret_key = \"my-secret-key\"
\t} Or indicates a Terraform module or configuration don't need
credentials at all, like provider `random`"
field as below.\n\tprovider \"aws\" {\n\t\tregion = \"us-west-2\"\n\t\taccess_key
= \"my-access-key\"\n\t\tsecret_key = \"my-secret-key\"\n\t}\nOr
indicates a Terraform module or configuration don't need credentials
at all, like provider `random`"
type: boolean
path:
description: Path is the sub-directory of remote git repository.
@ -282,22 +379,63 @@ spec:
required:
- name
type: object
JobEnv:
type: object
x-kubernetes-preserve-unknown-fields: true
remote:
description: Remote is a git repo which contains hcl files. Currently,
only public git repos are supported.
type: string
terraformCredentialsHelperConfigMapReference:
description: TerraformCredentialsHelperConfigMapReference specifies
the reference to a configmap containing the terraform registry credentials
helper
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
terraformCredentialsSecretReference:
description: TerraformCredentialsSecretReference specifies the reference
to the secret containing the terraform credentials and terraform
registry details
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
terraformRCConfigMapReference:
description: TerraformRCConfigMapReference specifies the reference
to a config map containing the terraform registry configuration
properties:
name:
description: name is unique within a namespace to reference a
secret resource.
type: string
namespace:
description: namespace defines the space within which the secret
name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
variable:
type: object
x-kubernetes-preserve-unknown-fields: true
writeConnectionSecretToRef:
description: WriteConnectionSecretToReference specifies the namespace
and name of a Secret to which any connection details for this managed
resource should be written. Connection details frequently include
the endpoint, username, and password required to connect to the
managed resource.
description: |-
WriteConnectionSecretToReference specifies the namespace and name of a
Secret to which any connection details for this managed resource should
be written. Connection details frequently include the endpoint, username,
and password required to connect to the managed resource.
properties:
name:
description: Name of the secret.
@ -327,8 +465,8 @@ spec:
type: object
type: object
region:
description: Region is the region for the cloud resources created
by this Configuration. If spec.region is not empty, it's the
description: |-
Region is the region for the cloud resources created by this Configuration. If spec.region is not empty, it's the
value of it. Otherwise, it's the value of spec.providerReference.region.
type: string
state:
@ -346,11 +484,10 @@ spec:
type: string
type: object
observedGeneration:
description: observedGeneration is the most recent generation observed
for this Configuration. It corresponds to the Configuration's generation,
which is updated on mutation by the API Server. If ObservedGeneration
equals Generation, and State is Available, the value of Outputs
is latest
description: |-
observedGeneration is the most recent generation observed for this Configuration. It corresponds to the
Configuration's generation, which is updated on mutation by the API Server.
If ObservedGeneration equals Generation, and State is Available, the value of Outputs is latest
format: int64
type: integer
type: object
@ -359,9 +496,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -1,11 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.6.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.16.5
name: providers.terraform.core.oam.dev
spec:
group: terraform.core.oam.dev
@ -29,14 +27,19 @@ spec:
description: Provider is the Schema for the providers 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'
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'
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
@ -47,8 +50,9 @@ spec:
description: Credentials required to authenticate to this provider.
properties:
secretRef:
description: A SecretRef is a reference to a secret key that contains
the credentials that must be used to connect to the provider.
description: |-
A SecretRef is a reference to a secret key that contains the credentials
that must be used to connect to the provider.
properties:
key:
description: The key to select.
@ -99,9 +103,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -24,6 +24,7 @@ spec:
{{- if .Values.controllerNamespace }}
- --controller-namespace={{ .Values.controllerNamespace }}
{{- end }}
- --feature-gates=AllowDeleteProvisioningResource={{ .Values.featureGates.AllowDeleteProvisioningResource }}
env:
- name: CONTROLLER_NAMESPACE
valueFrom:
@ -39,6 +40,10 @@ spec:
value: {{ .Values.gitImage}}
- name: GITHUB_BLOCKED
value: {{ .Values.githubBlocked }}
{{ if .Values.jobBackoffLimit }}
- name: JOB_BACKOFF_LIMIT
value: {{ .Values.jobBackoffLimit }}
{{ end }}
{{ if .Values.jobNodeSelector }}
- name: JOB_NODE_SELECTOR
value: {{ .Values.jobNodeSelector }}

View File

@ -2,26 +2,33 @@ replicaCount: 1
image:
repository: oamdev/terraform-controller
tag: 0.2.8
tag: latest
pullPolicy: Always
gitImage: alpine/git:latest
busyboxImage: busybox:latest
terraformImage: oamdev/docker-terraform:1.1.2
terraformImage: oamdev/docker-terraform:1.1.5
controllerNamespace: ""
# "{\"nat\": \"true\"}"
jobNodeSelector: ""
jobBackoffLimit: ""
resources:
limits:
cpu: "1000m"
memory: "2Gi"
cpu: "500m"
memory: "500Mi"
requests:
cpu: "1000m"
memory: "2Gi"
cpu: "250m"
memory: "250Mi"
backend:
namespace: vela-system
githubBlocked: "'false'"
featureGates:
# Enable the feature of allowing to delete a configuration whose cloud resources is not fully provisioned, or error happens
# This guarantees that the partial cloud resources will be deleted when the configuration is deleted
# Default value is true
AllowDeleteProvisioningResource: true

View File

@ -3,10 +3,11 @@ package backend
import (
"context"
"encoding/base64"
"gotest.tools/assert"
"reflect"
"testing"
"gotest.tools/assert"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

View File

@ -9,6 +9,7 @@ import (
"github.com/pkg/errors"
kerrors "k8s.io/apimachinery/pkg/api/errors"
apitypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
@ -16,6 +17,7 @@ import (
crossplane "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
"github.com/oam-dev/terraform-controller/api/v1beta1"
"github.com/oam-dev/terraform-controller/api/v1beta2"
"github.com/oam-dev/terraform-controller/controllers/features"
"github.com/oam-dev/terraform-controller/controllers/provider"
)
@ -82,9 +84,13 @@ func Get(ctx context.Context, k8sClient client.Client, namespacedName apitypes.N
// IsDeletable will check whether the Configuration can be deleted immediately
// If deletable, it means
// - feature gate AllowDeleteProvisioningResource is enabled
// - no external cloud resources are provisioned
// - it's in force-delete state
func IsDeletable(ctx context.Context, k8sClient client.Client, configuration *v1beta2.Configuration) (bool, error) {
if feature.DefaultFeatureGate.Enabled(features.AllowDeleteProvisioningResource) {
return true, nil
}
if configuration.Spec.ForceDelete != nil && *configuration.Spec.ForceDelete {
return true, nil
}
@ -115,7 +121,7 @@ func ReplaceTerraformSource(remote string, githubBlockedStr string) string {
klog.InfoS("Whether GitHub is blocked", "githubBlocked", githubBlockedStr)
githubBlocked, err := strconv.ParseBool(githubBlockedStr)
if err != nil {
klog.Warningf(errGitHubBlockedNotBoolean, err)
klog.Warningf("%s: %v", errGitHubBlockedNotBoolean, err)
return remote
}
klog.InfoS("Parsed GITHUB_BLOCKED env", "githubBlocked", githubBlocked)

View File

@ -96,7 +96,7 @@ func TestRawExtension2Map2(t *testing.T) {
},
},
want: want{
errMessage: "invalid character 'x' looking for beginning of value",
errMessage: "cannot convert RawExtension with unrecognized content type to unstructured",
},
}}
for name, tc := range cases {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
/*
Copyright 2023 The KubeVela 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 features
import (
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/component-base/featuregate"
)
const (
AllowDeleteProvisioningResource featuregate.Feature = "AllowDeleteProvisioningResource"
)
var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
AllowDeleteProvisioningResource: {Default: false, PreRelease: featuregate.Alpha},
}
func init() {
runtime.Must(feature.DefaultMutableFeatureGate.Add(defaultFeatureGates))
}

View File

@ -0,0 +1,60 @@
package container
import (
"fmt"
"github.com/oam-dev/terraform-controller/api/types"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
)
func (a *Assembler) ApplyContainer(executionType types.TerraformExecutionType, resourceQuota types.ResourceQuota) v1.Container {
c := v1.Container{
Name: types.TerraformContainerName,
Image: a.TerraformImage,
ImagePullPolicy: v1.PullIfNotPresent,
Command: []string{
"bash",
"-c",
fmt.Sprintf("terraform %s -lock=false -auto-approve", executionType),
},
VolumeMounts: []v1.VolumeMount{
{
Name: a.Name,
MountPath: types.WorkingVolumeMountPath,
},
{
Name: types.InputTFConfigurationVolumeName,
MountPath: types.InputTFConfigurationVolumeMountPath,
},
},
Env: a.Envs,
}
if resourceQuota.ResourcesLimitsCPU != "" || resourceQuota.ResourcesLimitsMemory != "" ||
resourceQuota.ResourcesRequestsCPU != "" || resourceQuota.ResourcesRequestsMemory != "" {
resourceRequirements := v1.ResourceRequirements{}
if resourceQuota.ResourcesLimitsCPU != "" || resourceQuota.ResourcesLimitsMemory != "" {
resourceRequirements.Limits = map[v1.ResourceName]resource.Quantity{}
if resourceQuota.ResourcesLimitsCPU != "" {
resourceRequirements.Limits["cpu"] = resourceQuota.ResourcesLimitsCPUQuantity
}
if resourceQuota.ResourcesLimitsMemory != "" {
resourceRequirements.Limits["memory"] = resourceQuota.ResourcesLimitsMemoryQuantity
}
}
if resourceQuota.ResourcesRequestsCPU != "" || resourceQuota.ResourcesLimitsMemory != "" {
resourceRequirements.Requests = map[v1.ResourceName]resource.Quantity{}
if resourceQuota.ResourcesRequestsCPU != "" {
resourceRequirements.Requests["cpu"] = resourceQuota.ResourcesRequestsCPUQuantity
}
if resourceQuota.ResourcesRequestsMemory != "" {
resourceRequirements.Requests["memory"] = resourceQuota.ResourcesRequestsMemoryQuantity
}
}
c.Resources = resourceRequirements
}
return c
}

View File

@ -0,0 +1,80 @@
package container
import (
"github.com/oam-dev/terraform-controller/api/types"
v1 "k8s.io/api/core/v1"
)
// Assembler helps to assemble the init containers
type Assembler struct {
Name string
GitCredential bool
TerraformCredential bool
TerraformRC bool
TerraformCredentialsHelper bool
TerraformImage string
BusyboxImage string
GitImage string
Git types.Git
Envs []v1.EnvVar
}
func NewAssembler(name string) *Assembler {
return &Assembler{Name: name}
}
func (a *Assembler) GitCredReference(ptr *v1.SecretReference) *Assembler {
if ptr != nil {
a.GitCredential = true
}
return a
}
func (a *Assembler) TerraformCredReference(ptr *v1.SecretReference) *Assembler {
if ptr != nil {
a.TerraformCredential = true
}
return a
}
func (a *Assembler) TerraformRCReference(ptr *v1.SecretReference) *Assembler {
if ptr != nil {
a.TerraformRC = true
}
return a
}
func (a *Assembler) TerraformCredentialsHelperReference(ptr *v1.SecretReference) *Assembler {
if ptr != nil {
a.TerraformCredentialsHelper = true
}
return a
}
func (a *Assembler) SetTerraformImage(image string) *Assembler {
a.TerraformImage = image
return a
}
func (a *Assembler) SetBusyboxImage(image string) *Assembler {
a.BusyboxImage = image
return a
}
func (a *Assembler) SetGitImage(image string) *Assembler {
a.GitImage = image
return a
}
func (a *Assembler) SetGit(git types.Git) *Assembler {
a.Git = git
return a
}
func (a *Assembler) SetEnvs(envs []v1.EnvVar) *Assembler {
a.Envs = envs
return a
}

View File

@ -0,0 +1,85 @@
package container
import (
"fmt"
"path/filepath"
"github.com/oam-dev/terraform-controller/api/types"
v1 "k8s.io/api/core/v1"
)
const GitContainerName = "git-configuration"
// GitContainer will clone the git repository, and copy the files to the working directory
func (a *Assembler) GitContainer() v1.Container {
mounts := []v1.VolumeMount{
{
Name: a.Name,
MountPath: types.WorkingVolumeMountPath,
},
{
Name: types.BackendVolumeName,
MountPath: types.BackendVolumeMountPath,
},
}
if a.GitCredential {
mounts = append(mounts,
v1.VolumeMount{
Name: types.GitAuthConfigVolumeName,
MountPath: types.GitAuthConfigVolumeMountPath,
})
}
command := a.getCloneCommand()
return v1.Container{
Name: GitContainerName,
Image: a.GitImage,
ImagePullPolicy: v1.PullIfNotPresent,
Command: command,
VolumeMounts: mounts,
}
}
func (a *Assembler) getCloneCommand() []string {
var cmd string
hclPath := filepath.Join(types.BackendVolumeMountPath, a.Git.Path)
copyCommand := fmt.Sprintf("cp -r %s/* %s", hclPath, types.WorkingVolumeMountPath)
checkoutCommand := ""
checkoutObject := getCheckoutObj(a.Git.Ref)
if checkoutObject != "" {
checkoutCommand = fmt.Sprintf("git checkout %s", checkoutObject)
}
cloneCommand := fmt.Sprintf("git clone %s %s", a.Git.URL, types.BackendVolumeMountPath)
// Check for git credentials, mount the SSH known hosts and private key, add private key into the SSH authentication agent
if a.GitCredential {
sshCommand := fmt.Sprintf("eval `ssh-agent` && ssh-add %s/%s", types.GitAuthConfigVolumeMountPath, v1.SSHAuthPrivateKey)
cloneCommand = fmt.Sprintf("%s && %s", sshCommand, cloneCommand)
}
cmd = cloneCommand
if checkoutCommand != "" {
cmd = fmt.Sprintf("%s && %s", cmd, checkoutCommand)
}
cmd = fmt.Sprintf("%s && %s", cmd, copyCommand)
command := []string{
"sh",
"-c",
cmd,
}
return command
}
func getCheckoutObj(ref types.GitRef) string {
if ref.Commit != "" {
return ref.Commit
} else if ref.Tag != "" {
return ref.Tag
}
return ref.Branch
}

View File

@ -0,0 +1,47 @@
package container
import (
"testing"
"github.com/oam-dev/terraform-controller/api/types"
)
func Test_getCheckoutObj(t *testing.T) {
tests := []struct {
name string
ref types.GitRef
want string
}{
{
name: "only branch",
ref: types.GitRef{
Branch: "feature",
},
want: "feature",
},
{
name: "tag take precedence over branch",
ref: types.GitRef{
Branch: "feature",
Tag: "v1.0.0",
},
want: "v1.0.0",
},
{
name: "commit take precedence over tag",
ref: types.GitRef{
Branch: "feature",
Tag: "v1.0.0",
Commit: "123456",
},
want: "123456",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := getCheckoutObj(tt.ref); got != tt.want {
t.Errorf("getCheckoutObj() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -0,0 +1,53 @@
package container
import (
"github.com/oam-dev/terraform-controller/api/types"
v1 "k8s.io/api/core/v1"
)
// InitContainer will run terraform init
func (a *Assembler) InitContainer() v1.Container {
mounts := []v1.VolumeMount{
{
Name: a.Name,
MountPath: types.WorkingVolumeMountPath,
},
}
if a.TerraformCredential {
mounts = append(mounts,
v1.VolumeMount{
Name: types.TerraformCredentialsConfigVolumeName,
MountPath: types.TerraformCredentialsConfigVolumeMountPath,
})
}
if a.TerraformRC {
mounts = append(mounts,
v1.VolumeMount{
Name: types.TerraformRCConfigVolumeName,
MountPath: types.TerraformRCConfigVolumeMountPath,
})
}
if a.TerraformCredentialsHelper {
mounts = append(mounts,
v1.VolumeMount{
Name: types.TerraformCredentialsHelperConfigVolumeName,
MountPath: types.TerraformCredentialsHelperConfigVolumeMountPath,
})
}
c := v1.Container{
Name: types.TerraformInitContainerName,
Image: a.TerraformImage,
ImagePullPolicy: v1.PullIfNotPresent,
Command: []string{
"sh",
"-c",
"terraform init",
},
VolumeMounts: mounts,
Env: a.Envs,
}
return c
}

View File

@ -0,0 +1,36 @@
package container
import (
"fmt"
"github.com/oam-dev/terraform-controller/api/types"
v1 "k8s.io/api/core/v1"
)
const InputContainerName = "prepare-input-terraform-configurations"
// InputContainer prepare input .tf files, copy them to the working directory
func (a *Assembler) InputContainer() v1.Container {
mounts := []v1.VolumeMount{
{
Name: a.Name,
MountPath: types.WorkingVolumeMountPath,
},
{
Name: types.InputTFConfigurationVolumeName,
MountPath: types.InputTFConfigurationVolumeMountPath,
},
}
return v1.Container{
Name: InputContainerName,
Image: a.BusyboxImage,
ImagePullPolicy: v1.PullIfNotPresent,
Command: []string{
"sh",
"-c",
fmt.Sprintf("cp %s/* %s", types.InputTFConfigurationVolumeMountPath, types.WorkingVolumeMountPath),
},
VolumeMounts: mounts,
}
}

View File

@ -0,0 +1,97 @@
package process
import (
"github.com/oam-dev/terraform-controller/api/types"
crossplane "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
"github.com/oam-dev/terraform-controller/api/v1beta2"
tfcfg "github.com/oam-dev/terraform-controller/controllers/configuration"
"github.com/oam-dev/terraform-controller/controllers/configuration/backend"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// LegacySubResources if user specify ControllerNamespace when re-staring controller, there are some sub-resources like Secret
// and ConfigMap that are in the namespace of the Configuration. We need to GC these sub-resources when Configuration is deleted.
type LegacySubResources struct {
// Namespace is the namespace of the Configuration, also the namespace of the sub-resources.
Namespace string
ApplyJobName string
DestroyJobName string
ConfigurationCMName string
VariableSecretName string
}
// TFConfigurationMeta is all the metadata of a Configuration
type TFConfigurationMeta struct {
Name string
Namespace string
ControllerNamespace string
ConfigurationType types.ConfigurationType
CompleteConfiguration string
Git types.Git
ConfigurationChanged bool
EnvChanged bool
ConfigurationCMName string
ApplyJobName string
DestroyJobName string
Envs []v1.EnvVar
ProviderReference *crossplane.Reference
VariableSecretName string
VariableSecretData map[string][]byte
DeleteResource bool
Region string
Credentials map[string]string
JobEnv map[string]interface{}
GitCredentialsSecretReference *v1.SecretReference
TerraformCredentialsSecretReference *v1.SecretReference
TerraformRCConfigMapReference *v1.SecretReference
TerraformCredentialsHelperConfigMapReference *v1.SecretReference
Backend backend.Backend
// JobNodeSelector Expose the node selector of job to the controller level
JobNodeSelector map[string]string
// TerraformImage is the Terraform image which can run `terraform init/plan/apply`
TerraformImage string
BusyboxImage string
GitImage string
// BackoffLimit specifies the number of retries to mark the Job as failed
BackoffLimit int32
// ResourceQuota series Variables are for Setting Compute Resources required by this container
ResourceQuota types.ResourceQuota
LegacySubResources LegacySubResources
ControllerNSSpecified bool
K8sClient client.Client
}
// TFState is Terraform State
type TFState struct {
Outputs map[string]TfStateProperty `json:"outputs"`
}
// TfStateProperty is the tf state property for an output
type TfStateProperty struct {
Value interface{} `json:"value,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// ToProperty converts TfStateProperty type to Property
func (tp *TfStateProperty) ToProperty() (v1beta2.Property, error) {
var (
property v1beta2.Property
err error
)
sv, err := tfcfg.Interface2String(tp.Value)
if err != nil {
return property, errors.Wrapf(err, "failed to convert value %s of terraform state outputs to string", tp.Value)
}
property = v1beta2.Property{
Value: sv,
}
return property, err
}

View File

@ -0,0 +1,757 @@
package process
import (
"context"
"encoding/json"
"fmt"
"os"
"reflect"
"github.com/oam-dev/terraform-controller/controllers/process/container"
"github.com/pkg/errors"
batchv1 "k8s.io/api/batch/v1"
v1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/terraform-controller/api/types"
"github.com/oam-dev/terraform-controller/api/v1beta1"
"github.com/oam-dev/terraform-controller/api/v1beta2"
tfcfg "github.com/oam-dev/terraform-controller/controllers/configuration"
"github.com/oam-dev/terraform-controller/controllers/configuration/backend"
"github.com/oam-dev/terraform-controller/controllers/provider"
"github.com/oam-dev/terraform-controller/controllers/util"
)
type Option func(spec v1beta2.Configuration, meta *TFConfigurationMeta)
// ControllerNamespaceOption will set the controller namespace for TFConfigurationMeta
func ControllerNamespaceOption(controllerNamespace string) Option {
return func(configuration v1beta2.Configuration, meta *TFConfigurationMeta) {
if controllerNamespace == "" {
return
}
uid := string(configuration.GetUID())
// @step: since we are using a single namespace to run these, we must ensure the names
// are unique across the namespace
meta.KeepLegacySubResourceMetas()
meta.ApplyJobName = uid + "-" + string(types.TerraformApply)
meta.DestroyJobName = uid + "-" + string(types.TerraformDestroy)
meta.ConfigurationCMName = fmt.Sprintf(types.TFInputConfigMapName, uid)
meta.VariableSecretName = fmt.Sprintf(types.TFVariableSecret, uid)
meta.ControllerNamespace = controllerNamespace
meta.ControllerNSSpecified = true
}
}
// New will create a new TFConfigurationMeta to process the configuration
func New(req ctrl.Request, configuration v1beta2.Configuration, k8sClient client.Client, option ...Option) *TFConfigurationMeta {
var meta = &TFConfigurationMeta{
ControllerNamespace: req.Namespace,
Namespace: req.Namespace,
Name: req.Name,
ConfigurationCMName: fmt.Sprintf(types.TFInputConfigMapName, req.Name),
VariableSecretName: fmt.Sprintf(types.TFVariableSecret, req.Name),
ApplyJobName: req.Name + "-" + string(types.TerraformApply),
DestroyJobName: req.Name + "-" + string(types.TerraformDestroy),
K8sClient: k8sClient,
}
jobNodeSelectorStr := os.Getenv("JOB_NODE_SELECTOR")
if jobNodeSelectorStr != "" {
err := json.Unmarshal([]byte(jobNodeSelectorStr), &meta.JobNodeSelector)
if err != nil {
klog.Warningf("the value of JobNodeSelector is not a json string: %v", err)
}
}
// githubBlocked mark whether GitHub is blocked in the cluster
githubBlockedStr := os.Getenv("GITHUB_BLOCKED")
if githubBlockedStr == "" {
githubBlockedStr = "false"
}
meta.Git.URL = tfcfg.ReplaceTerraformSource(configuration.Spec.Remote, githubBlockedStr)
if configuration.Spec.Path == "" {
meta.Git.Path = "."
} else {
meta.Git.Path = configuration.Spec.Path
}
if configuration.Spec.DeleteResource != nil {
meta.DeleteResource = *configuration.Spec.DeleteResource
} else {
meta.DeleteResource = true
}
if !configuration.Spec.InlineCredentials {
meta.ProviderReference = tfcfg.GetProviderNamespacedName(configuration)
}
if configuration.Spec.GitCredentialsSecretReference != nil {
meta.GitCredentialsSecretReference = configuration.Spec.GitCredentialsSecretReference
}
if configuration.Spec.TerraformCredentialsSecretReference != nil {
meta.TerraformCredentialsSecretReference = configuration.Spec.TerraformCredentialsSecretReference
}
if configuration.Spec.TerraformRCConfigMapReference != nil {
meta.TerraformRCConfigMapReference = configuration.Spec.TerraformRCConfigMapReference
}
if configuration.Spec.TerraformCredentialsHelperConfigMapReference != nil {
meta.TerraformCredentialsHelperConfigMapReference = configuration.Spec.TerraformCredentialsHelperConfigMapReference
}
for _, opt := range option {
opt(configuration, meta)
}
return meta
}
func (meta *TFConfigurationMeta) ValidateSecretAndConfigMap(ctx context.Context, k8sClient client.Client) error {
secretConfigMapToCheck := []struct {
ref *v1.SecretReference
notFoundState types.ConfigurationState
isSecret bool
neededKeys []string
errKey string
}{
{
ref: meta.GitCredentialsSecretReference,
notFoundState: types.InvalidGitCredentialsSecretReference,
isSecret: true,
neededKeys: []string{types.GitCredsKnownHosts, v1.SSHAuthPrivateKey},
errKey: "git credentials",
},
{
ref: meta.TerraformCredentialsSecretReference,
notFoundState: types.InvalidTerraformCredentialsSecretReference,
isSecret: true,
neededKeys: []string{types.TerraformCredentials},
errKey: "terraform credentials",
},
{
ref: meta.TerraformRCConfigMapReference,
notFoundState: types.InvalidTerraformRCConfigMapReference,
isSecret: false,
neededKeys: []string{types.TerraformRegistryConfig},
errKey: "terraformrc configuration",
},
{
ref: meta.TerraformCredentialsHelperConfigMapReference,
notFoundState: types.InvalidTerraformCredentialsHelperConfigMapReference,
isSecret: false,
neededKeys: []string{},
errKey: "terraform credentials helper",
},
}
for _, check := range secretConfigMapToCheck {
if check.ref != nil {
var object metav1.Object
var err error
object, err = GetSecretOrConfigMap(ctx, k8sClient, check.isSecret, check.ref, check.neededKeys, check.errKey)
if object == nil {
msg := string(check.notFoundState)
if err != nil {
msg = err.Error()
}
if updateStatusErr := meta.UpdateApplyStatus(ctx, k8sClient, check.notFoundState, msg); updateStatusErr != nil {
return errors.Wrap(updateStatusErr, msg)
}
return errors.New(msg)
}
// fix: The configmap or secret that the pod restricts from mounting must be in the same namespace as the pod,
// otherwise the volume mount will fail.
if object.GetNamespace() != meta.ControllerNamespace {
objectKind := "ConfigMap"
if check.isSecret {
objectKind = "Secret"
}
msg := fmt.Sprintf("Invalid %s '%s/%s', whose namespace '%s' is different from the Configuration, cannot mount the volume,"+
" you can fix this issue by creating the Secret/ConfigMap in the '%s' namespace.",
objectKind, object.GetNamespace(), object.GetName(), meta.ControllerNamespace, meta.ControllerNamespace)
if updateStatusErr := meta.UpdateApplyStatus(ctx, k8sClient, check.notFoundState, msg); updateStatusErr != nil {
return errors.Wrap(updateStatusErr, msg)
}
return errors.New(msg)
}
}
}
return nil
}
func (meta *TFConfigurationMeta) UpdateApplyStatus(ctx context.Context, k8sClient client.Client, state types.ConfigurationState, message string) error {
var configuration v1beta2.Configuration
if err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.Name, Namespace: meta.Namespace}, &configuration); err == nil {
configuration.Status.Apply = v1beta2.ConfigurationApplyStatus{
State: state,
Message: message,
Region: meta.Region,
}
configuration.Status.ObservedGeneration = configuration.Generation
if state == types.Available {
outputs, err := meta.getTFOutputs(ctx, k8sClient, configuration)
if err != nil {
klog.InfoS("Failed to get outputs", "error", err)
configuration.Status.Apply = v1beta2.ConfigurationApplyStatus{
State: types.GeneratingOutputs,
Message: types.ErrGenerateOutputs + ": " + err.Error(),
}
} else {
configuration.Status.Apply.Outputs = outputs
}
}
return k8sClient.Status().Update(ctx, &configuration)
}
return nil
}
func (meta *TFConfigurationMeta) UpdateDestroyStatus(ctx context.Context, k8sClient client.Client, state types.ConfigurationState, message string) error {
var configuration v1beta2.Configuration
if err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.Name, Namespace: meta.Namespace}, &configuration); err == nil {
configuration.Status.Destroy = v1beta2.ConfigurationDestroyStatus{
State: state,
Message: message,
}
return k8sClient.Status().Update(ctx, &configuration)
}
return nil
}
func (meta *TFConfigurationMeta) AssembleAndTriggerJob(ctx context.Context, k8sClient client.Client, executionType types.TerraformExecutionType) error {
// apply rbac
if err := createTerraformExecutorServiceAccount(ctx, k8sClient, meta.ControllerNamespace, types.ServiceAccountName); err != nil {
return err
}
if err := util.CreateTerraformExecutorClusterRoleBinding(ctx, k8sClient, meta.ControllerNamespace, fmt.Sprintf("%s-%s", meta.ControllerNamespace, types.ClusterRoleName), types.ServiceAccountName); err != nil {
return err
}
job := meta.assembleTerraformJob(executionType)
return k8sClient.Create(ctx, job)
}
// UpdateTerraformJobIfNeeded will set deletion finalizer to the Terraform job if its envs are changed, which will result in
// deleting the job. Finally, a new Terraform job will be generated
func (meta *TFConfigurationMeta) UpdateTerraformJobIfNeeded(ctx context.Context, k8sClient client.Client, job batchv1.Job) error {
// if either one changes, delete the job
if meta.EnvChanged || meta.ConfigurationChanged {
klog.InfoS("about to delete job", "Name", job.Name, "Namespace", job.Namespace)
var j batchv1.Job
if err := k8sClient.Get(ctx, client.ObjectKey{Name: job.Name, Namespace: job.Namespace}, &j); err == nil {
if deleteErr := k8sClient.Delete(ctx, &job, client.PropagationPolicy(metav1.DeletePropagationBackground)); deleteErr != nil {
return deleteErr
}
}
var s v1.Secret
if err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.VariableSecretName, Namespace: meta.ControllerNamespace}, &s); err == nil {
if deleteErr := k8sClient.Delete(ctx, &s); deleteErr != nil {
return deleteErr
}
}
}
return nil
}
func (meta *TFConfigurationMeta) assembleTerraformJob(executionType types.TerraformExecutionType) *batchv1.Job {
var (
initContainers []v1.Container
parallelism int32 = 1
completions int32 = 1
)
executorVolumes := meta.assembleExecutorVolumes()
assembler := container.NewAssembler(meta.Name).
TerraformCredReference(meta.TerraformCredentialsSecretReference).
TerraformRCReference(meta.TerraformRCConfigMapReference).
TerraformCredentialsHelperReference(meta.TerraformCredentialsHelperConfigMapReference).
GitCredReference(meta.GitCredentialsSecretReference).
SetGit(meta.Git).
SetBusyboxImage(meta.BusyboxImage).
SetTerraformImage(meta.TerraformImage).
SetGitImage(meta.GitImage).
SetEnvs(meta.Envs)
initContainers = append(initContainers, assembler.InputContainer())
if meta.Git.URL != "" {
initContainers = append(initContainers, assembler.GitContainer())
}
initContainers = append(initContainers, assembler.InitContainer())
applyContainer := assembler.ApplyContainer(executionType, meta.ResourceQuota)
name := meta.ApplyJobName
if executionType == types.TerraformDestroy {
name = meta.DestroyJobName
}
return &batchv1.Job{
TypeMeta: metav1.TypeMeta{
Kind: "Job",
APIVersion: "batch/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: meta.ControllerNamespace,
},
Spec: batchv1.JobSpec{
Parallelism: &parallelism,
Completions: &completions,
BackoffLimit: &meta.BackoffLimit,
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
// This annotation will prevent istio-proxy sidecar injection in the pods
// as having the sidecar would have kept the Job in `Running` state and would
// not transition to `Completed`
"sidecar.istio.io/inject": "false",
},
},
Spec: v1.PodSpec{
// InitContainer will copy Terraform configuration files to working directory and create Terraform
// state file directory in advance
InitContainers: initContainers,
// Container terraform-executor will first copy predefined terraform.d to working directory, and
// then run terraform init/apply.
Containers: []v1.Container{applyContainer},
ServiceAccountName: types.ServiceAccountName,
Volumes: executorVolumes,
RestartPolicy: v1.RestartPolicyOnFailure,
NodeSelector: meta.JobNodeSelector,
},
},
},
}
}
func (meta *TFConfigurationMeta) assembleExecutorVolumes() []v1.Volume {
workingVolume := v1.Volume{Name: meta.Name}
workingVolume.EmptyDir = &v1.EmptyDirVolumeSource{}
inputTFConfigurationVolume := meta.createConfigurationVolume()
tfBackendVolume := meta.createTFBackendVolume()
executorVolumes := []v1.Volume{workingVolume, inputTFConfigurationVolume, tfBackendVolume}
secretOrConfigMapReferences := []struct {
ref *v1.SecretReference
volumeName string
isSecret bool
}{
{
ref: meta.GitCredentialsSecretReference,
volumeName: types.GitAuthConfigVolumeName,
isSecret: true,
},
{
ref: meta.TerraformCredentialsSecretReference,
volumeName: types.TerraformCredentialsConfigVolumeName,
isSecret: true,
},
{
ref: meta.TerraformRCConfigMapReference,
volumeName: types.TerraformRCConfigVolumeName,
isSecret: false,
},
{
ref: meta.TerraformCredentialsHelperConfigMapReference,
volumeName: types.TerraformCredentialsHelperConfigVolumeName,
isSecret: false,
},
}
for _, ref := range secretOrConfigMapReferences {
if ref.ref != nil {
executorVolumes = append(executorVolumes, meta.createSecretOrConfigMapVolume(ref.isSecret, ref.ref.Name, ref.volumeName))
}
}
return executorVolumes
}
func (meta *TFConfigurationMeta) createConfigurationVolume() v1.Volume {
inputCMVolumeSource := v1.ConfigMapVolumeSource{}
inputCMVolumeSource.Name = meta.ConfigurationCMName
inputTFConfigurationVolume := v1.Volume{Name: types.InputTFConfigurationVolumeName}
inputTFConfigurationVolume.ConfigMap = &inputCMVolumeSource
return inputTFConfigurationVolume
}
func (meta *TFConfigurationMeta) createTFBackendVolume() v1.Volume {
gitVolume := v1.Volume{Name: types.BackendVolumeName}
gitVolume.EmptyDir = &v1.EmptyDirVolumeSource{}
return gitVolume
}
func (meta *TFConfigurationMeta) createSecretOrConfigMapVolume(isSecret bool, secretOrConfigMapReferenceName string, volumeName string) v1.Volume {
var defaultMode int32 = 0400
volume := v1.Volume{Name: volumeName}
if isSecret {
volumeSource := v1.SecretVolumeSource{}
volumeSource.SecretName = secretOrConfigMapReferenceName
volumeSource.DefaultMode = &defaultMode
volume.Secret = &volumeSource
} else {
volumeSource := v1.ConfigMapVolumeSource{}
volumeSource.Name = secretOrConfigMapReferenceName
volumeSource.DefaultMode = &defaultMode
volume.ConfigMap = &volumeSource
}
return volume
}
func (meta *TFConfigurationMeta) KeepLegacySubResourceMetas() {
meta.LegacySubResources.Namespace = meta.Namespace
meta.LegacySubResources.ApplyJobName = meta.ApplyJobName
meta.LegacySubResources.DestroyJobName = meta.DestroyJobName
meta.LegacySubResources.ConfigurationCMName = meta.ConfigurationCMName
meta.LegacySubResources.VariableSecretName = meta.VariableSecretName
}
func (meta *TFConfigurationMeta) GetApplyJob(ctx context.Context, k8sClient client.Client, job *batchv1.Job) error {
if err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.LegacySubResources.ApplyJobName, Namespace: meta.LegacySubResources.Namespace}, job); err == nil {
klog.InfoS("Found legacy apply job", "Configuration", fmt.Sprintf("%s/%s", meta.Name, meta.Namespace),
"Job", fmt.Sprintf("%s/%s", meta.LegacySubResources.Namespace, meta.LegacySubResources.ApplyJobName))
return nil
}
err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.ApplyJobName, Namespace: meta.ControllerNamespace}, job)
return err
}
// RenderConfiguration will compose the Terraform configuration with hcl/json and backend
func (meta *TFConfigurationMeta) RenderConfiguration(configuration *v1beta2.Configuration, configurationType types.ConfigurationType) (string, backend.Backend, error) {
backendInterface, err := backend.ParseConfigurationBackend(configuration, meta.K8sClient, meta.Credentials, meta.ControllerNSSpecified)
if err != nil {
return "", nil, errors.Wrap(err, "failed to prepare Terraform backend configuration")
}
switch configurationType {
case types.ConfigurationHCL:
completedConfiguration := configuration.Spec.HCL
completedConfiguration += "\n" + backendInterface.HCL()
return completedConfiguration, backendInterface, nil
case types.ConfigurationRemote:
return backendInterface.HCL(), backendInterface, nil
default:
return "", nil, errors.New("Unsupported Configuration Type")
}
}
func (meta *TFConfigurationMeta) IsTFStateGenerated(ctx context.Context) bool {
// 1. exist backend
if meta.Backend == nil {
return false
}
// 2. and exist tfstate file
_, err := meta.Backend.GetTFStateJSON(ctx)
return err == nil
}
//nolint:funlen
func (meta *TFConfigurationMeta) getTFOutputs(ctx context.Context, k8sClient client.Client, configuration v1beta2.Configuration) (map[string]v1beta2.Property, error) {
var tfStateJSON []byte
var err error
if meta.Backend != nil {
tfStateJSON, err = meta.Backend.GetTFStateJSON(ctx)
if err != nil {
return nil, err
}
}
var tfState TFState
if err := json.Unmarshal(tfStateJSON, &tfState); err != nil {
return nil, err
}
outputs := make(map[string]v1beta2.Property)
for k, v := range tfState.Outputs {
property, err := v.ToProperty()
if err != nil {
return outputs, err
}
outputs[k] = property
}
writeConnectionSecretToReference := configuration.Spec.WriteConnectionSecretToReference
if writeConnectionSecretToReference == nil || writeConnectionSecretToReference.Name == "" {
return outputs, nil
}
name := writeConnectionSecretToReference.Name
ns := writeConnectionSecretToReference.Namespace
if ns == "" {
ns = types.DefaultNamespace
}
data := make(map[string][]byte)
for k, v := range outputs {
data[k] = []byte(v.Value)
}
var gotSecret v1.Secret
configurationName := configuration.ObjectMeta.Name
if err := k8sClient.Get(ctx, client.ObjectKey{Name: name, Namespace: ns}, &gotSecret); err != nil {
if kerrors.IsNotFound(err) {
var secret = v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: ns,
Labels: map[string]string{
"terraform.core.oam.dev/created-by": "terraform-controller",
"terraform.core.oam.dev/owned-by": configurationName,
"terraform.core.oam.dev/owned-namespace": configuration.Namespace,
},
},
TypeMeta: metav1.TypeMeta{Kind: "Secret"},
Data: data,
}
err = k8sClient.Create(ctx, &secret)
if kerrors.IsAlreadyExists(err) {
return nil, fmt.Errorf("secret(%s) already exists", name)
} else if err != nil {
return nil, err
}
}
} else {
// check the owner of this secret
labels := gotSecret.ObjectMeta.Labels
ownerName := labels["terraform.core.oam.dev/owned-by"]
ownerNamespace := labels["terraform.core.oam.dev/owned-namespace"]
if (ownerName != "" && ownerName != configurationName) ||
(ownerNamespace != "" && ownerNamespace != configuration.Namespace) {
errMsg := fmt.Sprintf(
"configuration(namespace: %s ; name: %s) cannot update secret(namespace: %s ; name: %s) whose owner is configuration(namespace: %s ; name: %s)",
configuration.Namespace, configurationName,
gotSecret.Namespace, name,
ownerNamespace, ownerName,
)
klog.ErrorS(err, "fail to update backend secret")
return nil, errors.New(errMsg)
}
gotSecret.Data = data
if err := k8sClient.Update(ctx, &gotSecret); err != nil {
return nil, err
}
}
return outputs, nil
}
func (meta *TFConfigurationMeta) PrepareTFVariables(configuration *v1beta2.Configuration) error {
var (
envs []v1.EnvVar
data = map[string][]byte{}
)
if configuration == nil {
return errors.New("configuration is nil")
}
if !configuration.Spec.InlineCredentials && meta.ProviderReference == nil {
return errors.New("The referenced provider could not be retrieved")
}
tfVariable, err := getTerraformJSONVariable(configuration.Spec.Variable)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to get Terraform JSON variables from Configuration Variables %v", configuration.Spec.Variable))
}
for k, v := range tfVariable {
envValue, err := tfcfg.Interface2String(v)
if err != nil {
return err
}
data[k] = []byte(envValue)
}
if !configuration.Spec.InlineCredentials && meta.Credentials == nil {
return errors.New(provider.ErrCredentialNotRetrieved)
}
for k, v := range meta.Credentials {
data[k] = []byte(v)
}
for k, v := range meta.JobEnv {
envValue, err := tfcfg.Interface2String(v)
if err != nil {
return err
}
data[k] = []byte(envValue)
}
for k := range data {
valueFrom := &v1.EnvVarSource{SecretKeyRef: &v1.SecretKeySelector{Key: k}}
valueFrom.SecretKeyRef.Name = meta.VariableSecretName
envs = append(envs, v1.EnvVar{Name: k, ValueFrom: valueFrom})
}
meta.Envs = envs
meta.VariableSecretData = data
return nil
}
// GetCredentials will get credentials from secret of the Provider
func (meta *TFConfigurationMeta) GetCredentials(ctx context.Context, k8sClient client.Client, providerObj *v1beta1.Provider) error {
region, err := tfcfg.SetRegion(ctx, k8sClient, meta.Namespace, meta.Name, providerObj)
if err != nil {
return err
}
credentials, err := provider.GetProviderCredentials(ctx, k8sClient, providerObj, region)
if err != nil {
return err
}
if credentials == nil {
return errors.New(provider.ErrCredentialNotRetrieved)
}
meta.Credentials = credentials
meta.Region = region
return nil
}
func (meta *TFConfigurationMeta) createOrUpdateConfigMap(ctx context.Context, k8sClient client.Client, data map[string]string) error {
var gotCM v1.ConfigMap
if err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.ConfigurationCMName, Namespace: meta.ControllerNamespace}, &gotCM); err != nil {
if !kerrors.IsNotFound(err) {
return err
}
cm := v1.ConfigMap{
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "ConfigMap"},
ObjectMeta: metav1.ObjectMeta{
Name: meta.ConfigurationCMName,
Namespace: meta.ControllerNamespace,
},
Data: data,
}
if err := k8sClient.Create(ctx, &cm); err != nil {
return errors.Wrap(err, "failed to create TF configuration ConfigMap")
}
return nil
}
if !reflect.DeepEqual(gotCM.Data, data) {
gotCM.Data = data
return errors.Wrap(k8sClient.Update(ctx, &gotCM), "failed to update TF configuration ConfigMap")
}
return nil
}
func (meta *TFConfigurationMeta) prepareTFInputConfigurationData() map[string]string {
var dataName string
switch meta.ConfigurationType {
case types.ConfigurationHCL:
dataName = types.TerraformHCLConfigurationName
case types.ConfigurationRemote:
dataName = "terraform-backend.tf"
}
data := map[string]string{dataName: meta.CompleteConfiguration, "kubeconfig": ""}
return data
}
// StoreTFConfiguration will store Terraform configuration to ConfigMap
func (meta *TFConfigurationMeta) StoreTFConfiguration(ctx context.Context, k8sClient client.Client) error {
data := meta.prepareTFInputConfigurationData()
return meta.createOrUpdateConfigMap(ctx, k8sClient, data)
}
// CheckWhetherConfigurationChanges will check whether configuration is changed
func (meta *TFConfigurationMeta) CheckWhetherConfigurationChanges(ctx context.Context, k8sClient client.Client, configurationType types.ConfigurationType) error {
switch configurationType {
case types.ConfigurationHCL:
var cm v1.ConfigMap
if err := k8sClient.Get(ctx, client.ObjectKey{Name: meta.ConfigurationCMName, Namespace: meta.ControllerNamespace}, &cm); err != nil {
if kerrors.IsNotFound(err) {
return nil
}
return err
}
meta.ConfigurationChanged = cm.Data[types.TerraformHCLConfigurationName] != meta.CompleteConfiguration
if meta.ConfigurationChanged {
klog.InfoS("Configuration HCL changed", "ConfigMap", cm.Data[types.TerraformHCLConfigurationName],
"RenderedCompletedConfiguration", meta.CompleteConfiguration)
}
return nil
case types.ConfigurationRemote:
meta.ConfigurationChanged = false
return nil
default:
return errors.New("unsupported configuration type, only HCL or Remote is supported")
}
}
func GetSecretOrConfigMap(ctx context.Context, k8sClient client.Client, isSecret bool, ref *v1.SecretReference, neededKeys []string, errKey string) (metav1.Object, error) {
secret := &v1.Secret{}
configMap := &v1.ConfigMap{}
var err error
// key to determine if it is a secret or config map
var typeKey string
if isSecret {
namespacedName := client.ObjectKey{Name: ref.Name, Namespace: ref.Namespace}
err = k8sClient.Get(ctx, namespacedName, secret)
typeKey = "secret"
} else {
namespacedName := client.ObjectKey{Name: ref.Name, Namespace: ref.Namespace}
err = k8sClient.Get(ctx, namespacedName, configMap)
typeKey = "configmap"
}
errMsg := fmt.Sprintf("Failed to get %s %s", errKey, typeKey)
if err != nil {
klog.ErrorS(err, errMsg, "Name", ref.Name, "Namespace", ref.Namespace)
return nil, errors.Wrap(err, errMsg)
}
for _, key := range neededKeys {
var keyErr bool
if isSecret {
if _, ok := secret.Data[key]; !ok {
keyErr = true
}
} else {
if _, ok := configMap.Data[key]; !ok {
keyErr = true
}
}
if keyErr {
keyErr := errors.Errorf("'%s' not in %s %s", key, errKey, typeKey)
return nil, keyErr
}
}
if isSecret {
return secret, nil
}
return configMap, nil
}
func createTerraformExecutorServiceAccount(ctx context.Context, k8sClient client.Client, namespace, serviceAccountName string) error {
var serviceAccount = v1.ServiceAccount{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ServiceAccount",
},
ObjectMeta: metav1.ObjectMeta{
Name: serviceAccountName,
Namespace: namespace,
},
}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: serviceAccountName, Namespace: namespace}, &v1.ServiceAccount{}); err != nil {
if kerrors.IsNotFound(err) {
if err := k8sClient.Create(ctx, &serviceAccount); err != nil {
return errors.Wrap(err, "failed to create ServiceAccount for Terraform executor")
}
}
}
return nil
}
func getTerraformJSONVariable(tfVariables *runtime.RawExtension) (map[string]interface{}, error) {
variables, err := tfcfg.RawExtension2Map(tfVariables)
if err != nil {
return nil, err
}
var environments = make(map[string]interface{})
for k, v := range variables {
environments[fmt.Sprintf("TF_VAR_%s", k)] = v
}
return environments, nil
}

File diff suppressed because it is too large Load Diff

View File

@ -51,9 +51,9 @@ const (
// AlibabaCloudCredentials are credentials for Alibaba Cloud
type AlibabaCloudCredentials struct {
AccessKeyID string `yaml:"accessKeyID"`
AccessKeySecret string `yaml:"accessKeySecret"`
SecurityToken string `yaml:"securityToken"`
AccessKeyID string `yaml:"accessKeyID" json:"accessKeyID,omitempty"`
AccessKeySecret string `yaml:"accessKeySecret" json:"accessKeySecret,omitempty"`
SecurityToken string `yaml:"securityToken" json:"securityToken,omitempty"`
}
// GetProviderCredentials gets provider credentials by cloud provider name

View File

@ -7,7 +7,6 @@ import (
"testing"
. "github.com/agiledragon/gomonkey/v2"
"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
"github.com/google/go-cmp/cmp"
"github.com/jinzhu/copier"
"github.com/stretchr/testify/assert"
@ -109,10 +108,8 @@ func TestGetProviderCredentials(t *testing.T) {
}
assert.Nil(t, k8sClient1.Create(ctx, secret))
patches := ApplyMethod(reflect.TypeOf(&sts.Client{}), "GetCallerIdentity", func(_ *sts.Client, request *sts.GetCallerIdentityRequest) (response *sts.GetCallerIdentityResponse, err error) {
response = nil
err = nil
return
patches := ApplyFunc(checkAlibabaCloudCredentials, func(region, accessKeyID, accessKeySecret, stsToken string) error {
return nil
})
defer patches.Reset()

View File

@ -30,7 +30,7 @@ func TestReconcile(t *testing.T) {
s := runtime.NewScheme()
v1beta1.AddToScheme(s)
v1.AddToScheme(s)
r1.Client = fake.NewClientBuilder().WithScheme(s).Build()
r1.Client = fake.NewClientBuilder().WithScheme(s).WithStatusSubresource(&v1beta1.Provider{}).Build()
r2 := &ProviderReconciler{}
provider2 := &v1beta1.Provider{
@ -69,7 +69,7 @@ func TestReconcile(t *testing.T) {
Type: v1.SecretTypeOpaque,
}
r2.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(secret2, provider2).Build()
r2.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(secret2, provider2).WithStatusSubresource(&v1beta1.Provider{}).Build()
r3 := &ProviderReconciler{}
provider3 := &v1beta1.Provider{
@ -92,7 +92,7 @@ func TestReconcile(t *testing.T) {
},
}
r3.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider3).Build()
r3.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider3).WithStatusSubresource(&v1beta1.Provider{}).Build()
r4 := &ProviderReconciler{}
provider4 := &v1beta1.Provider{
@ -105,7 +105,7 @@ func TestReconcile(t *testing.T) {
Provider: "aws",
},
}
r4.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider4).Build()
r4.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider4).WithStatusSubresource(&v1beta1.Provider{}).Build()
r5 := &ProviderReconciler{}
provider5 := &v1beta1.Provider{
@ -118,7 +118,7 @@ func TestReconcile(t *testing.T) {
Provider: "aws",
},
}
r5.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider5).Build()
r5.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider5).WithStatusSubresource(&v1beta1.Provider{}).Build()
type args struct {
req reconcile.Request
@ -238,7 +238,7 @@ func TestReconcileProviderIsReadyButFailedToUpdateStatus(t *testing.T) {
Type: v1.SecretTypeOpaque,
}
r2.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(secret2, provider2).Build()
r2.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(secret2, provider2).WithStatusSubresource(&v1beta1.Provider{}).Build()
patches := ApplyFunc(apiutil.GVKForObject, func(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) {
switch obj.(type) {
@ -321,7 +321,7 @@ func TestReconcile3(t *testing.T) {
},
}
r3.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider3).Build()
r3.Client = fake.NewClientBuilder().WithScheme(s).WithObjects(provider3).WithStatusSubresource(&v1beta1.Provider{}).Build()
patches := ApplyFunc(apiutil.GVKForObject, func(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) {
switch obj.(type) {

View File

@ -18,15 +18,16 @@ package controllers
import (
"path/filepath"
"reflect"
"testing"
. "github.com/agiledragon/gomonkey/v2"
. "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"
// +kubebuilder:scaffold:imports
@ -40,12 +41,20 @@ var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
func init() {
patches := NewPatches()
patches.ApplyMethod(reflect.TypeOf(&envtest.Environment{}), "Start", func(_ *envtest.Environment) (*rest.Config, error) {
return &rest.Config{}, nil
})
patches.ApplyMethod(reflect.TypeOf(&envtest.Environment{}), "Stop", func(_ *envtest.Environment) error {
return nil
})
}
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
"Controller Suite",
[]Reporter{printer.NewlineReporter{}})
RunSpecs(t, "Controller Suite")
}
var _ = BeforeSuite(func() {

View File

@ -30,7 +30,7 @@ func getPods(ctx context.Context, client kubernetes.Interface, namespace, jobNam
func getPodLog(ctx context.Context, client kubernetes.Interface, namespace, jobName, containerName, initContainerName string) (types.Stage, string, error) {
var (
targetContainer = containerName
stage = types.TerraformApply
stage = types.ApplyStage
)
pods, err := getPods(ctx, client, namespace, jobName)
if err != nil || pods == nil || len(pods.Items) == 0 {
@ -44,7 +44,7 @@ func getPodLog(ctx context.Context, client kubernetes.Interface, namespace, jobN
for _, c := range pod.Status.InitContainerStatuses {
if c.Name == initContainerName && !c.Ready {
targetContainer = initContainerName
stage = types.TerraformInit
stage = types.InitStage
break
}
}

View File

@ -89,7 +89,7 @@ func TestGetPodLog(t *testing.T) {
initContainerName: "terraform-init",
},
want: want{
errMsg: "can not be accept",
errMsg: "client rate limiter Wait returned an error: can not be accept",
},
},
}

View File

@ -35,6 +35,7 @@ func GetTerraformStatus(ctx context.Context, jobNamespace, jobName, containerNam
return state, errors.New(errMsg)
}
// analyzeTerraformLog will analyze the logs of Terraform apply pod, returns true if check is ok.
func analyzeTerraformLog(logs string, stage types.Stage) (bool, types.ConfigurationState, string) {
lines := strings.Split(logs, "\n")
for i, line := range lines {
@ -44,9 +45,9 @@ func analyzeTerraformLog(logs string, stage types.Stage) (bool, types.Configurat
return false, types.InvalidRegion, errMsg
}
switch stage {
case types.TerraformInit:
case types.InitStage:
return false, types.TerraformInitError, errMsg
case types.TerraformApply:
case types.ApplyStage:
return false, types.ConfigurationApplyFailed, errMsg
}
}

View File

@ -143,7 +143,7 @@ func TestAnalyzeTerraformLog(t *testing.T) {
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
success, state, errMsg := analyzeTerraformLog(tc.args.logs, types.TerraformApply)
success, state, errMsg := analyzeTerraformLog(tc.args.logs, types.ApplyStage)
if tc.want.errMsg != "" {
assert.Contains(t, errMsg, tc.want.errMsg)
} else {

View File

@ -1,18 +1,17 @@
package controllers
package util
import (
"context"
"fmt"
"github.com/pkg/errors"
v1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
func createTerraformExecutorClusterRole(ctx context.Context, k8sClient client.Client, clusterRoleName string) error {
func CreateTerraformExecutorClusterRole(ctx context.Context, k8sClient client.Client, clusterRoleName string) error {
var clusterRole = rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
@ -44,7 +43,7 @@ func createTerraformExecutorClusterRole(ctx context.Context, k8sClient client.Cl
return nil
}
func createTerraformExecutorClusterRoleBinding(ctx context.Context, k8sClient client.Client, namespace, clusterRoleName, serviceAccountName string) error {
func CreateTerraformExecutorClusterRoleBinding(ctx context.Context, k8sClient client.Client, namespace, clusterRoleName, serviceAccountName string) error {
var crbName = fmt.Sprintf("%s-tf-executor-clusterrole-binding", namespace)
var clusterRoleBinding = rbacv1.ClusterRoleBinding{
TypeMeta: metav1.TypeMeta{
@ -77,24 +76,3 @@ func createTerraformExecutorClusterRoleBinding(ctx context.Context, k8sClient cl
}
return nil
}
func createTerraformExecutorServiceAccount(ctx context.Context, k8sClient client.Client, namespace, serviceAccountName string) error {
var serviceAccount = v1.ServiceAccount{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ServiceAccount",
},
ObjectMeta: metav1.ObjectMeta{
Name: serviceAccountName,
Namespace: namespace,
},
}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: serviceAccountName, Namespace: namespace}, &v1.ServiceAccount{}); err != nil {
if kerrors.IsNotFound(err) {
if err := k8sClient.Create(ctx, &serviceAccount); err != nil {
return errors.Wrap(err, "failed to create ServiceAccount for Terraform executor")
}
}
}
return nil
}

View File

@ -0,0 +1,56 @@
package util
import (
"context"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
rbacv1 "k8s.io/api/rbac/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
)
var (
env envtest.Environment
k8sClient client.Client
)
var _ = BeforeSuite(func() {
env = envtest.Environment{}
cfg, err := env.Start()
Expect(err).To(BeNil())
Expect(cfg).ToNot(BeNil())
k8sClient, err = client.New(cfg, client.Options{})
Expect(err).To(BeNil())
})
var _ = AfterSuite(func() {
err := env.Stop()
Expect(err).To(BeNil())
})
var _ = Describe("Utils", func() {
roleName := "default-tf-executor-clusterrole"
It("CreateTerraformExecutorClusterRole", func() {
err := CreateTerraformExecutorClusterRole(context.TODO(), k8sClient, roleName)
Expect(err).To(BeNil())
// Get and examine the role
role := &rbacv1.ClusterRole{}
err = k8sClient.Get(context.TODO(), client.ObjectKey{
Name: roleName,
}, role)
Expect(err).To(BeNil())
Expect(len(role.Rules)).To(Equal(2))
Expect(role.Rules[0].Resources).To(Equal([]string{"secrets"}))
Expect(role.Rules[0].Verbs).To(Equal([]string{"get", "list", "create", "update", "delete"}))
Expect(role.Rules[1].Resources).To(Equal([]string{"leases"}))
Expect(role.Rules[1].Verbs).To(Equal([]string{"get", "create", "update", "delete"}))
})
It("CreateTerraformExecutorClusterRoleBinding", func() {
err := CreateTerraformExecutorClusterRoleBinding(context.TODO(), k8sClient, "default", roleName, "tf-executor-service-account")
Expect(err).To(BeNil())
})
})

View File

@ -0,0 +1,53 @@
package util
import (
"context"
"fmt"
"reflect"
"testing"
. "github.com/agiledragon/gomonkey/v2"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/envtest"
)
func init() {
patches := ApplyMethod(reflect.TypeOf(&envtest.Environment{}), "Start", func(_ *envtest.Environment) (*rest.Config, error) {
return &rest.Config{}, nil
})
patches.ApplyMethod(reflect.TypeOf(&envtest.Environment{}), "Stop", func(_ *envtest.Environment) error {
return nil
})
patches.ApplyFunc(CreateTerraformExecutorClusterRole, func(ctx context.Context, c client.Client, name string) error {
role := &rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{Name: name},
Rules: []rbacv1.PolicyRule{
{Resources: []string{"secrets"}, Verbs: []string{"get", "list", "create", "update", "delete"}},
{APIGroups: []string{"coordination.k8s.io"}, Resources: []string{"leases"}, Verbs: []string{"get", "create", "update", "delete"}},
},
}
return c.Create(ctx, role)
})
patches.ApplyFunc(CreateTerraformExecutorClusterRoleBinding, func(ctx context.Context, c client.Client, namespace, clusterRoleName, serviceAccountName string) error {
crb := &rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%s-tf-executor-clusterrole-binding", namespace), Namespace: namespace},
RoleRef: rbacv1.RoleRef{APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: clusterRoleName},
Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: serviceAccountName, Namespace: namespace}},
}
return c.Create(ctx, crb)
})
patches.ApplyFunc(client.New, func(_ *rest.Config, _ client.Options) (client.Client, error) {
return fake.NewClientBuilder().Build(), nil
})
}
func TestUtils(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Utils Suite")
}

View File

@ -2,10 +2,11 @@ package controllernamespace
import (
"context"
types2 "github.com/oam-dev/terraform-controller/api/types"
"strings"
"time"
types2 "github.com/oam-dev/terraform-controller/api/types"
crossplane "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

View File

@ -2,15 +2,18 @@ package normal
import (
"context"
"encoding/base64"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"text/template"
"time"
"gotest.tools/assert"
coreV1 "k8s.io/api/core/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
@ -28,9 +31,10 @@ var (
"examples/alibaba/eip/configuration_eip_remote_subdirectory.yaml",
"examples/alibaba/oss/configuration_hcl_bucket.yaml",
}
testConfigurationsForceDelete = "examples/random/configuration_force_delete.yaml"
chartNamespace = "terraform"
testConfigurationsForceDelete = "examples/random/configuration_force_delete.yaml"
testConfigurationsGitCredsSecretReference = "examples/random/configuration_git_ssh.yaml"
testConfigurationDeleteProvisioningResources = "examples/random/configuration_delete_provisioning_resources.yaml"
chartNamespace = "terraform"
)
type ConfigurationAttr struct {
@ -54,7 +58,9 @@ type DoFunc = func(ctx *TestContext)
type Injector struct {
BeforeApplyConfiguration DoFunc
CheckConfiguration DoFunc
CleanUp DoFunc
// add more actions and check points if needed
}
@ -67,6 +73,36 @@ func invoke(do DoFunc, ctx *TestContext) {
func testBase(t *testing.T, configuration ConfigurationAttr, injector Injector, useCustomBackend bool) {
klog.Infof("%s test begins……", configuration.Name)
waitConfigurationAvailable := func(ctx *TestContext) {
for i := 0; i < 60; i++ {
var fields []string
output, err := exec.Command("bash", "-c", "kubectl get configuration").CombinedOutput()
assert.NilError(t, err)
t.Log("get configuration\n", string(output))
lines := strings.Split(string(output), "\n")
for i, line := range lines {
if i == 0 {
continue
}
fields = strings.Fields(line)
if len(fields) == 3 && fields[0] == configuration.Name && fields[1] == Available {
return
}
}
output, err = exec.Command("bash", "-c", "kubectl get pod").CombinedOutput()
lines = strings.Split(string(output), "\n")
t.Log("get pod\n", string(output))
if i == 59 {
t.Error("Configuration is not ready, getting controller's log")
output, err = exec.Command("bash", "-c", "kubectl logs -n terraform deploy/terraform-controller").CombinedOutput()
assert.NilError(t, err)
t.Log(string(output))
}
time.Sleep(time.Second * 2)
}
}
backendSecretNamespace := configuration.BackendStateSecretNS
if backendSecretNamespace == "" {
backendSecretNamespace = os.Getenv("TERRAFORM_BACKEND_NAMESPACE")
@ -91,34 +127,17 @@ func testBase(t *testing.T, configuration ConfigurationAttr, injector Injector,
klog.Info("1. Applying Configuration")
invoke(injector.BeforeApplyConfiguration, testCtx)
pwd, _ := os.Getwd()
configuration.YamlPath = filepath.Join(pwd, "..", configuration.YamlPath)
configuration.YamlPath = filepath.Join(pwd, "../..", configuration.YamlPath)
cmd := fmt.Sprintf("kubectl apply -f %s", configuration.YamlPath)
err = exec.Command("bash", "-c", cmd).Start()
assert.NilError(t, err)
output, err := exec.Command("bash", "-c", cmd).CombinedOutput()
assert.NilError(t, err, string(output))
klog.Info("2. Checking Configuration status")
for i := 0; i < 120; i++ {
var fields []string
output, err := exec.Command("bash", "-c", "kubectl get configuration").Output()
assert.NilError(t, err)
lines := strings.Split(string(output), "\n")
for i, line := range lines {
if i == 0 {
continue
}
fields = strings.Fields(line)
if len(fields) == 3 && fields[0] == configuration.Name && fields[1] == Available {
goto continueCheck
}
}
if i == 119 {
t.Error("Configuration is not ready")
}
time.Sleep(time.Second * 5)
if injector.CheckConfiguration == nil {
injector.CheckConfiguration = waitConfigurationAvailable
}
invoke(injector.CheckConfiguration, testCtx)
continueCheck:
klog.Info("3. Checking the status of Configs and Secrets")
klog.Info("- Checking ConfigMap which stores .tf")
@ -131,9 +150,11 @@ continueCheck:
assert.NilError(t, err)
}
klog.Info("- Checking Secret which stores outputs")
_, err = clientSet.CoreV1().Secrets("default").Get(ctx, configuration.OutputsSecretName, v1.GetOptions{})
assert.NilError(t, err)
if configuration.OutputsSecretName != "" {
klog.Info("- Checking Secret which stores outputs")
_, err = clientSet.CoreV1().Secrets("default").Get(ctx, configuration.OutputsSecretName, v1.GetOptions{})
assert.NilError(t, err)
}
klog.Info("- Checking Secret which stores variables")
_, err = clientSet.CoreV1().Secrets("default").Get(ctx, configuration.VariableSecretName, v1.GetOptions{})
@ -141,8 +162,8 @@ continueCheck:
klog.Info("4. Deleting Configuration")
cmd = fmt.Sprintf("kubectl delete -f %s", configuration.YamlPath)
err = exec.Command("bash", "-c", cmd).Start()
assert.NilError(t, err)
output, err = exec.Command("bash", "-c", cmd).CombinedOutput()
assert.NilError(t, err, string(output))
klog.Info("5. Checking Configuration is deleted")
for i := 0; i < 60; i++ {
@ -150,8 +171,8 @@ continueCheck:
fields []string
existed bool
)
output, err := exec.Command("bash", "-c", "kubectl get configuration").Output()
assert.NilError(t, err)
output, err := exec.Command("bash", "-c", "kubectl get configuration").CombinedOutput()
assert.NilError(t, err, string(output))
lines := strings.Split(string(output), "\n")
@ -178,8 +199,10 @@ continueCheck:
klog.Info("6. Checking Secrets and ConfigMap which should all be deleted")
_, err = clientSet.CoreV1().Secrets("default").Get(ctx, configuration.OutputsSecretName, v1.GetOptions{})
assert.Equal(t, kerrors.IsNotFound(err), true)
if configuration.OutputsSecretName != "" {
_, err = clientSet.CoreV1().Secrets("default").Get(ctx, configuration.OutputsSecretName, v1.GetOptions{})
assert.Equal(t, kerrors.IsNotFound(err), true)
}
_, err = clientSet.CoreV1().Secrets("default").Get(ctx, configuration.VariableSecretName, v1.GetOptions{})
assert.Equal(t, kerrors.IsNotFound(err), true)
@ -218,14 +241,14 @@ func TestInlineCredentialsConfigurationUseCustomBackendKubernetes(t *testing.T)
VariableSecretName: "variable-random-e2e-custom-backend-kubernetes",
}
beforeApply := func(ctx *TestContext) {
cmd := exec.Command("bash", "-c", "kubectl create ns a")
err := cmd.Run()
assert.NilError(t, err)
output, err := exec.Command("bash", "-c", "kubectl create ns a").CombinedOutput()
if err != nil && !strings.Contains(string(output), "already exists") {
assert.NilError(t, err, string(output))
}
}
cleanUp := func(ctx *TestContext) {
cmd := exec.Command("bash", "-c", "kubectl delete ns a")
err := cmd.Run()
assert.NilError(t, err)
output, err := exec.Command("bash", "-c", "kubectl delete ns a").CombinedOutput()
assert.NilError(t, err, string(output))
}
testBase(
t,
@ -257,7 +280,7 @@ func TestForceDeleteConfiguration(t *testing.T) {
fields []string
existed bool
)
output, err := exec.Command("bash", "-c", "kubectl get configuration").Output()
output, err := exec.Command("bash", "-c", "kubectl get configuration").CombinedOutput()
assert.NilError(t, err)
lines := strings.Split(string(output), "\n")
@ -284,6 +307,147 @@ func TestForceDeleteConfiguration(t *testing.T) {
}
}
func TestGitCredentialsSecretReference(t *testing.T) {
configuration := ConfigurationAttr{
Name: "random-e2e-git-creds-secret-ref",
YamlPath: testConfigurationsGitCredsSecretReference,
TFConfigMapName: "tf-random-e2e-git-creds-secret-ref",
BackendStateSecretName: "tfstate-default-random-e2e-git-creds-secret-ref",
OutputsSecretName: "random-e2e-git-creds-secret-ref-conn",
VariableSecretName: "variable-random-e2e-git-creds-secret-ref",
}
clientSet, err := client.Init()
assert.NilError(t, err)
pwd, _ := os.Getwd()
gitServer := filepath.Join(pwd, "../..", "examples/git-credentials")
gitServerApplyCmd := fmt.Sprintf("kubectl apply -f %s", gitServer)
gitServerDeleteCmd := fmt.Sprintf("kubectl delete -f %s", gitServer)
gitSshAuthSecretYaml := filepath.Join(gitServer, "git-ssh-auth-secret.yaml")
beforeApply := func(ctx *TestContext) {
output, err := exec.Command("bash", "-c", gitServerApplyCmd).CombinedOutput()
assert.NilError(t, err, string(output))
klog.Info("- Checking git-server pod status")
for i := 0; i < 120; i++ {
serverReady := false
pushReady := false
pod, _ := clientSet.CoreV1().Pods("default").Get(ctx, "git-server", v1.GetOptions{})
conditions := pod.Status.Conditions
var index int
for count, condition := range conditions {
index = count
if condition.Status == "True" && condition.Type == coreV1.PodReady {
klog.Info("- pod=git-server ", condition.Type, "=", condition.Status)
break
}
}
if conditions[index].Status == "True" && conditions[index].Type == coreV1.PodReady {
serverReady = true
}
job, _ := clientSet.BatchV1().Jobs("default").Get(ctx, "git-push", v1.GetOptions{})
if job.Status.Succeeded == 1 {
pushReady = true
}
if serverReady && pushReady {
break
}
if i == 119 {
t.Error("git-server pod is not running")
}
time.Sleep(10 * time.Second)
}
getKnownHostsCmd := "kubectl exec pod/git-server -- ssh-keyscan git-server"
knownHosts, err := exec.Command("bash", "-c", getKnownHostsCmd).CombinedOutput()
assert.NilError(t, err)
gitSshAuthSecretTmpl := filepath.Join(gitServer, "templates/git-ssh-auth-secret.tmpl")
tmpl := template.Must(template.ParseFiles(gitSshAuthSecretTmpl))
gitSshAuthSecretYamlFile, err := os.Create(gitSshAuthSecretYaml)
assert.NilError(t, err)
err = tmpl.Execute(gitSshAuthSecretYamlFile, base64.StdEncoding.EncodeToString(knownHosts))
assert.NilError(t, err)
err = exec.Command("bash", "-c", gitServerApplyCmd).Run()
assert.NilError(t, err)
}
cleanUp := func(ctx *TestContext) {
err = exec.Command("bash", "-c", gitServerDeleteCmd).Run()
assert.NilError(t, err)
os.Remove(gitSshAuthSecretYaml)
}
testBase(
t,
configuration,
Injector{
BeforeApplyConfiguration: beforeApply,
CleanUp: cleanUp,
},
false,
)
}
func TestAllowDeleteProvisioningResoruce(t *testing.T) {
configuration := ConfigurationAttr{
Name: "random-e2e-delete-provisioning-resources",
YamlPath: testConfigurationDeleteProvisioningResources,
TFConfigMapName: "tf-random-e2e-delete-provisioning-resources",
BackendStateSecretName: "tfstate-default-random-e2e-delete-provisioning-resources",
// won't generate output at all
OutputsSecretName: "",
VariableSecretName: "variable-random-e2e-delete-provisioning-resources",
}
checkConfigurationIsProvisioning := func(ctx *TestContext) {
for i := 0; i < 20; i++ {
cfgProvisioning := false
backendExist := false
klog.Info("Check configuration is provisioning")
var fields []string
output, err := exec.Command("bash", "-c", "kubectl get configuration").CombinedOutput()
assert.NilError(t, err)
lines := strings.Split(string(output), "\n")
for i, line := range lines {
if i == 0 {
continue
}
fields = strings.Fields(line)
if len(fields) == 3 && fields[0] == configuration.Name && fields[1] == Provisioning {
cfgProvisioning = true
}
}
_, err = ctx.ClientSet.CoreV1().Secrets(ctx.BackendSecretNamespace).Get(ctx, configuration.BackendStateSecretName, v1.GetOptions{})
if err == nil {
backendExist = true
}
if cfgProvisioning && backendExist {
return
}
if i == 119 {
t.Error("Configuration is not ready")
}
time.Sleep(time.Second * 5)
}
}
testBase(
t,
configuration,
Injector{
CheckConfiguration: checkConfigurationIsProvisioning,
},
false,
)
}
//func TestBasicConfigurationRegression(t *testing.T) {
// var retryTimes = 120
//

View File

@ -15,6 +15,7 @@ import (
// Available is the available status of Configuration
const Available = "Available"
const Provisioning = "ProvisioningAndChecking"
// Regression test for the e2e.
func Regression(t *testing.T, testcases []string, retryTimes int) {
@ -103,8 +104,7 @@ deletion:
time.Sleep(time.Second * 5)
continue
} else {
break
}
break
}
}

View File

@ -0,0 +1,86 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: simple-terraform-module
namespace: default
data:
main.tf: |
resource "tls_private_key" "private_key" {
algorithm = var.algorithm
}
outputs.tf: |
output "openssh_private_key" {
value = nonsensitive(tls_private_key.private_key.private_key_pem)
}
variables.tf: |
variable "algorithm" {
description = "Encryption algorithm for the private key"
type = string
}
---
apiVersion: batch/v1
kind: Job
metadata:
name: git-push
namespace: default
labels:
name: git-push
spec:
template:
spec:
restartPolicy: OnFailure
initContainers:
- name: wait-for-git-server
image: alpine/git
command:
- sh
- -c
- >-
set -x &&
until nc -vzw 2 git-server 22; do sleep 10; done
volumeMounts:
- mountPath: /usr/.ssh
name: ssh-keys
containers:
- name: git-push
image: alpine/git
command:
- sh
- -c
- >-
set -x &&
eval $(ssh-agent) &&
ssh-add /usr/.ssh/id_rsa &&
mkdir /root/.ssh &&
ssh-keyscan git-server >> /root/.ssh/known_hosts &&
mkdir /usr/simple-terraform-module &&
cd /usr/simple-terraform-module &&
cp /simple-terraform-module/*.tf . &&
git config --global init.defaultBranch master &&
git init &&
git config user.name "john.doe" &&
git config user.email "john@doe.com" &&
git add . &&
git commit -m "initial commit" &&
git remote add origin git@git-server:simple-terraform-module.git &&
git push --set-upstream origin master
volumeMounts:
- mountPath: /usr/.ssh
name: ssh-keys
- mountPath: /simple-terraform-module
name: simple-terraform-module
resources:
limits:
memory: "128Mi"
cpu: "0.1"
volumes:
- name: ssh-keys
secret:
secretName: ssh-keys
items:
- key: id_rsa
path: id_rsa
defaultMode: 0400
- name: simple-terraform-module
configMap:
name: simple-terraform-module

View File

@ -0,0 +1,85 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: init-git-server-script
namespace: default
data:
init-git-server.sh: |
#!/bin/sh
set -x
mkdir -p ~/.ssh
chmod 0700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
mkdir simple-terraform-module.git
git config --global init.defaultBranch master &>/dev/null
git init --bare simple-terraform-module.git
---
apiVersion: v1
kind: Pod
metadata:
name: git-server
namespace: default
labels:
name: git-server
spec:
containers:
- name: git-server
image: ubuntu:22.04
command:
- sh
- -c
- >-
apt update &&
apt install git openssh-server -y &&
mkdir /var/run/sshd &&
useradd -r -m -U -d /home/git -s /bin/bash git &&
su - git -c /tmp/scripts/init-git-server.sh &&
cat ~/.ssh/authorized_keys >> /home/git/.ssh/authorized_keys &&
/usr/sbin/sshd -D
lifecycle:
preStop:
exec:
command:
- sh
- -c
- service ssh stop
volumeMounts:
- mountPath: /root/.ssh
name: ssh-keys
- mountPath: /tmp/scripts
name: init-git-server
ports:
- containerPort: 22
readinessProbe:
tcpSocket:
port: 22
initialDelaySeconds: 30
resources:
limits:
memory: "500Mi"
cpu: "0.2"
volumes:
- name: ssh-keys
secret:
secretName: ssh-keys
items:
- key: id_rsa.pub
path: authorized_keys
- name: init-git-server
configMap:
name: init-git-server-script
defaultMode: 0555
---
apiVersion: v1
kind: Service
metadata:
name: git-server
namespace: default
spec:
ports:
- port: 22
protocol: TCP
targetPort: 22
selector:
name: git-server

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: ssh-keys
namespace: default
type: Opaque
data:
id_rsa: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBbCtDTXIvbXl4eDlrNnJoUTlvbXhEQk1ZemYvMTJwTisvb24zSjJTTTVQUjhndFdOCk1mL2taWmdGQWNHYk55T3o5emI4MFVqTWNKY2lCNXdzNFVBcTJEa2ZzU090dllQbW5Nand2dUJId3p3cmpBcEgKT1ZVN1ozbjQ2VUpya2crUkVoWElVbGRYcXQzellOSllWZXF3MHhTOTBpNFNyR1RLS3VrR1FGQVh1L3Q5YzBERApDNHFGZXk1UXlQYndxMWFhN01uVDlqRHZvdWQxMjhtUnZoSzNSQkxZQjE3SURIQ3o4bURQNllkYVJJLys5MHdTCkh3c0dTdk44K3FtbTdzazFkdkJ2RkhNTllnaDl2S09mbDNuQitOOWlNQ2pOV1BvMFdBZkl1VHVCU0ozMnVHZ3UKdkxSZFJocXVpWlAyenpraEhpSnUzdHlVWDRWWHp2TXMwdSsyY1FJREFRQUJBb0lCQVFDS2ZVZk1iM1NGL2lxWApuZHExOUhocytqejBHeUtrWFRyQUFDNU96WEZzbFVPMFNlYW1ZU0J6UTF2TmJpMks2aE9BcWJOL1kxS0ltRWQvCmlQbWpyRTlsT3pHYTVWM1lJaDUzZVFPT0NoVm1BY2Z6dXF1WHJCQ3ZHcG5PbWJKZFRiU0xPVEdoWStPYyt5YWkKY3l2NXJEZnhRa2lWRDA0WHhSQlVjSWd5dk5Ybm90UHcwbmVEVHhISDN5N3VWL0tLRE9YUjVWdmZ3RzJJelpzRQp0UUNtejRRUHNRYUpLOGdMYk1BTC8xTmcwV0oxUjI0UFhlMzlid3ZqRytnMC9MYmFrcFB4YTJ2Tjc1VmZScEJXCjdaYVd3L2ZGWStwYjdjdENCSGVFQ3E1T1I1L0lOWGJuVEFUMHJKTlM0eEdEeUR6am9hOGtGamR0bGU0bmdKU2YKaG1wbFdxa0JBb0dCQU1Md3pZRDBEMEhxTWswZ3VuWlNsTDBhK3ZzdFF5S1VwOURvTHNSRnFNeEgrakt3c1J4eApWaE1nVzQrTEpSenllV0lPOWJWajkrZUY1SUxsQXo3WithQVNYdjVVdHlVSzJyM1I4N3FCcjFTMDhjS3hlYi9hCjVualBHbkl6aEVTOHNXRExmS2N6MkhYMnF5MWlsL1NNdloyQ2JZMllLYVk4ekNrU1JDQ2FIS2ZGQW9HQkFNZHkKdWhmN29DK0Z6dUtoanUzQ3l0aU1EZGhybDVhWVBmdWxWTHNlamxYR1ZxWU1nZDRXNzg5QTdCbUJZMERzdmh6RwprRnZ0bWhzUEw3RGhEdUZ2bGtvdnVkS25XbTJvUjZqbDFGNkZWSGxzN3lIS3FTQ2R2bjdXL0ZhZSsxL1loOFFSCk8vR2lBY1c2UTJuMHhVOTBVVmwvMnlVZGhHakVKSGN2S3hCcnpCSzlBb0dCQUpqWjdaanVSVVJlMlFBbTZHMjgKaE1uZWJPc2o2MThqQm83RWIxOFFhN0Y1d3BHYWY5VVlmUEJVVDlhMnVPd0FwL0tlWGtUVFZOK2gyYkpVMVgyagp0cHF2clBKcEJJMnovQjRZa0s0dDM0ZGd0YXYrTXNPZlpWVld0cHJURUNSQmZDZTBobElvVWRMMURmVnhPRXJWClRCeEQxNWpOdGVLV0MxTXM4bVJKMHF3dEFvR0FNbFUrcDJ6RitSaEFwS3IyNGdQRm95NTlFLy9iQ3BNekdUMloKQzN2am1idnJCQTZsKzRFNFZjcGhpdkkvTlJSSnlnTkdUUnpDUmsvbnpqQ055OUNZVWZLSFo2VDZTakFzblhBYQp6eHZBdk1BRC9UZ2l4R3RxdHFIVW5wdVNmcGFyZEl5UTN5THVaWkxqRG10S0hBb1R1WTF0cFlrMGNDZ0h0OWc4CmV2RnBWOVVDZ1lBejlmMk9ISzNVR254dDZOOXM0ZVpUak9TVDRSWUVzR0JOZ1pSV0JVc0pHMkRJdkE2Sks3T3QKc3hwTWwzYUpLVWFCWmswS3FReVlrNTkrRTRkeis4UFZjVmN1bGoxQUtYRVR1a3BQaUU3ZFhlTXpjaUxSNUt4YwpvVmFoWVFXSlg0N016aFVTMWxJSVFJcmlsN0JTNmFnbTlnV2NoVkpIVGNHYVY1ZFZBdmI2VXc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
id_rsa.pub: c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCQVFDWDRJeXYrYkxISDJUcXVGRDJpYkVNRXhqTi8vWGFrMzcraWZjblpJems5SHlDMVkweC8rUmxtQVVCd1pzM0k3UDNOdnpSU014d2x5SUhuQ3poUUNyWU9SK3hJNjI5ZythY3lQQys0RWZEUEN1TUNrYzVWVHRuZWZqcFFtdVNENUVTRmNoU1YxZXEzZk5nMGxoVjZyRFRGTDNTTGhLc1pNb3E2UVpBVUJlNyszMXpRTU1MaW9WN0xsREk5dkNyVnByc3lkUDJNTytpNTNYYnlaRytFcmRFRXRnSFhzZ01jTFB5WU0vcGgxcEVqLzczVEJJZkN3Wks4M3o2cWFidXlUVjI4RzhVY3cxaUNIMjhvNStYZWNINDMySXdLTTFZK2pSWUI4aTVPNEZJbmZhNGFDNjh0RjFHR3E2SmsvYlBPU0VlSW03ZTNKUmZoVmZPOHl6Uzc3WngK

View File

@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: git-ssh-auth
namespace: default
type: kubernetes.io/ssh-auth
data:
ssh-privatekey: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBbCtDTXIvbXl4eDlrNnJoUTlvbXhEQk1ZemYvMTJwTisvb24zSjJTTTVQUjhndFdOCk1mL2taWmdGQWNHYk55T3o5emI4MFVqTWNKY2lCNXdzNFVBcTJEa2ZzU090dllQbW5Nand2dUJId3p3cmpBcEgKT1ZVN1ozbjQ2VUpya2crUkVoWElVbGRYcXQzellOSllWZXF3MHhTOTBpNFNyR1RLS3VrR1FGQVh1L3Q5YzBERApDNHFGZXk1UXlQYndxMWFhN01uVDlqRHZvdWQxMjhtUnZoSzNSQkxZQjE3SURIQ3o4bURQNllkYVJJLys5MHdTCkh3c0dTdk44K3FtbTdzazFkdkJ2RkhNTllnaDl2S09mbDNuQitOOWlNQ2pOV1BvMFdBZkl1VHVCU0ozMnVHZ3UKdkxSZFJocXVpWlAyenpraEhpSnUzdHlVWDRWWHp2TXMwdSsyY1FJREFRQUJBb0lCQVFDS2ZVZk1iM1NGL2lxWApuZHExOUhocytqejBHeUtrWFRyQUFDNU96WEZzbFVPMFNlYW1ZU0J6UTF2TmJpMks2aE9BcWJOL1kxS0ltRWQvCmlQbWpyRTlsT3pHYTVWM1lJaDUzZVFPT0NoVm1BY2Z6dXF1WHJCQ3ZHcG5PbWJKZFRiU0xPVEdoWStPYyt5YWkKY3l2NXJEZnhRa2lWRDA0WHhSQlVjSWd5dk5Ybm90UHcwbmVEVHhISDN5N3VWL0tLRE9YUjVWdmZ3RzJJelpzRQp0UUNtejRRUHNRYUpLOGdMYk1BTC8xTmcwV0oxUjI0UFhlMzlid3ZqRytnMC9MYmFrcFB4YTJ2Tjc1VmZScEJXCjdaYVd3L2ZGWStwYjdjdENCSGVFQ3E1T1I1L0lOWGJuVEFUMHJKTlM0eEdEeUR6am9hOGtGamR0bGU0bmdKU2YKaG1wbFdxa0JBb0dCQU1Md3pZRDBEMEhxTWswZ3VuWlNsTDBhK3ZzdFF5S1VwOURvTHNSRnFNeEgrakt3c1J4eApWaE1nVzQrTEpSenllV0lPOWJWajkrZUY1SUxsQXo3WithQVNYdjVVdHlVSzJyM1I4N3FCcjFTMDhjS3hlYi9hCjVualBHbkl6aEVTOHNXRExmS2N6MkhYMnF5MWlsL1NNdloyQ2JZMllLYVk4ekNrU1JDQ2FIS2ZGQW9HQkFNZHkKdWhmN29DK0Z6dUtoanUzQ3l0aU1EZGhybDVhWVBmdWxWTHNlamxYR1ZxWU1nZDRXNzg5QTdCbUJZMERzdmh6RwprRnZ0bWhzUEw3RGhEdUZ2bGtvdnVkS25XbTJvUjZqbDFGNkZWSGxzN3lIS3FTQ2R2bjdXL0ZhZSsxL1loOFFSCk8vR2lBY1c2UTJuMHhVOTBVVmwvMnlVZGhHakVKSGN2S3hCcnpCSzlBb0dCQUpqWjdaanVSVVJlMlFBbTZHMjgKaE1uZWJPc2o2MThqQm83RWIxOFFhN0Y1d3BHYWY5VVlmUEJVVDlhMnVPd0FwL0tlWGtUVFZOK2gyYkpVMVgyagp0cHF2clBKcEJJMnovQjRZa0s0dDM0ZGd0YXYrTXNPZlpWVld0cHJURUNSQmZDZTBobElvVWRMMURmVnhPRXJWClRCeEQxNWpOdGVLV0MxTXM4bVJKMHF3dEFvR0FNbFUrcDJ6RitSaEFwS3IyNGdQRm95NTlFLy9iQ3BNekdUMloKQzN2am1idnJCQTZsKzRFNFZjcGhpdkkvTlJSSnlnTkdUUnpDUmsvbnpqQ055OUNZVWZLSFo2VDZTakFzblhBYQp6eHZBdk1BRC9UZ2l4R3RxdHFIVW5wdVNmcGFyZEl5UTN5THVaWkxqRG10S0hBb1R1WTF0cFlrMGNDZ0h0OWc4CmV2RnBWOVVDZ1lBejlmMk9ISzNVR254dDZOOXM0ZVpUak9TVDRSWUVzR0JOZ1pSV0JVc0pHMkRJdkE2Sks3T3QKc3hwTWwzYUpLVWFCWmswS3FReVlrNTkrRTRkeis4UFZjVmN1bGoxQUtYRVR1a3BQaUU3ZFhlTXpjaUxSNUt4YwpvVmFoWVFXSlg0N016aFVTMWxJSVFJcmlsN0JTNmFnbTlnV2NoVkpIVGNHYVY1ZFZBdmI2VXc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
known_hosts: {{ . }}

View File

@ -0,0 +1,18 @@
apiVersion: terraform.core.oam.dev/v1beta2
kind: Configuration
metadata:
name: random-e2e-delete-provisioning-resources
spec:
hcl: |
resource "random_id" "server" {
byte_length = 8
}
resource "random_id" "error" {
byte_length = -1
}
inlineCredentials: true
writeConnectionSecretToRef:
name: random-conn
namespace: default

View File

@ -0,0 +1,15 @@
apiVersion: terraform.core.oam.dev/v1beta2
kind: Configuration
metadata:
name: random-e2e-git-creds-secret-ref
spec:
inlineCredentials: true
remote: git@git-server:simple-terraform-module.git
variable:
algorithm: RSA
writeConnectionSecretToRef:
name: random-e2e-git-creds-secret-ref-conn
gitCredentialsSecretReference:
name: git-ssh-auth
namespace: default

View File

@ -495,7 +495,7 @@ es-connection Opaque 1 7m37s
## KubeVela Terraform Addon
Terraform Controller is well integrated in [KubeVela](https://github.com/oam-dev/kubevela) as a Terraform addon. Enabling
Terraform Controller is well integrated in [KubeVela](https://github.com/kubevela/kubevela) as a Terraform addon. Enabling
Terraform addon and Terraform provider addon is the simplest way.
- Install Terraform Controller

View File

@ -1,8 +1,9 @@
package gitee
import (
"github.com/oam-dev/terraform-controller/e2e/normal"
"testing"
"github.com/oam-dev/terraform-controller/e2e/normal"
)
var (

107
go.mod
View File

@ -1,81 +1,92 @@
module github.com/oam-dev/terraform-controller
go 1.17
go 1.23.8
require (
github.com/agiledragon/gomonkey/v2 v2.4.0
github.com/agiledragon/gomonkey/v2 v2.9.0
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1384
github.com/aws/aws-sdk-go v1.44.23
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v0.4.0
github.com/google/go-cmp v0.5.7
github.com/go-logr/logr v1.4.2
github.com/google/go-cmp v0.6.0
github.com/hashicorp/hcl/v2 v2.12.0
github.com/jinzhu/copier v0.3.5
github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.19.0
github.com/onsi/gomega v1.33.1
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v2 v2.4.0
gotest.tools v2.2.0+incompatible
k8s.io/api v0.21.3
k8s.io/apimachinery v0.21.3
k8s.io/client-go v0.21.3
k8s.io/klog/v2 v2.8.0
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471
sigs.k8s.io/controller-runtime v0.9.5
sigs.k8s.io/yaml v1.2.0
k8s.io/api v0.31.10
k8s.io/apimachinery v0.31.10
k8s.io/apiserver v0.31.10
k8s.io/client-go v0.31.10
k8s.io/component-base v0.31.10
k8s.io/klog/v2 v2.130.1
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
sigs.k8s.io/controller-runtime v0.19.1
sigs.k8s.io/yaml v1.4.0
)
require github.com/kylelemons/godebug v1.1.0 // indirect
require (
github.com/agext/levenshtein v1.2.3 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/evanphx/json-patch v4.11.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-test/deep v1.0.7 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.11 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.26.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/zclconf/go-cty v1.10.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.26.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.3.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/apiextensions-apiserver v0.21.3 // indirect
k8s.io/component-base v0.21.3 // indirect
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.31.10 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)
replace github.com/jmespath/go-jmespath v0.4.0 => github.com/cloud-native-application/go-jmespath v0.5.0

762
go.sum
View File

@ -1,440 +1,192 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
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.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
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/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
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/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
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/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agiledragon/gomonkey/v2 v2.4.0 h1:YDQJYiSQ8o78dCMXehU1E4F/Kh4jPX+MV+/iK/yfL7s=
github.com/agiledragon/gomonkey/v2 v2.4.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
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/agiledragon/gomonkey/v2 v2.9.0 h1:PDiKKybR596O6FHW+RVSG0Z7uGCBNbmbUXh3uCNQ7Hc=
github.com/agiledragon/gomonkey/v2 v2.9.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1384 h1:hJm7oFzY49BcC2Kd5o8tyDWv3xFNop6bTmon9phd74w=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1384/go.mod h1:9CMdKNL3ynIGPpfTcdwTvIm8SGuAZYYC4jFVSSvE1YQ=
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0=
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.44.23 h1:oFvpKJk5qdprnCcuCWk2/CADdvfYtyduQ392bMXjlYI=
github.com/aws/aws-sdk-go v1.44.23/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
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.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloud-native-application/go-jmespath v0.5.0 h1:nsiXjYDvYwvWrzDEhx8M4mg96yzdPFQWlf2rouH6eEA=
github.com/cloud-native-application/go-jmespath v0.5.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
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/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
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/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
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/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
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-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/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-20191227052852-215e87163ea7/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/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/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.1.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/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.3.4/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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
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-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
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-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
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.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
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/hcl/v2 v2.12.0 h1:PsYxySWpMD4KPaoJLnsHwtK5Qptvj/4Q6s0t4sUxZf4=
github.com/hashicorp/hcl/v2 v2.12.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg=
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/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
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/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
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-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
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-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
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/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
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 v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
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/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey 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.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
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/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
@ -442,371 +194,137 @@ github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUA
github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8=
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.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
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.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
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=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/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-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/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
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.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180811021610-c39426892332/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-20181023162649-9b4f9f5ad519/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-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-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-20190620200207-3b0461eec859/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-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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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/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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/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/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
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/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-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-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-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/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-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/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-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/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-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-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-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
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.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
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/grpc v1.27.1/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/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
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.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.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.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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.21.3 h1:cblWILbLO8ar+Fj6xdDGr603HRsf8Wu9E9rngJeprZQ=
k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg=
k8s.io/apiextensions-apiserver v0.21.3 h1:+B6biyUWpqt41kz5x6peIsljlsuwvNAp/oFax/j2/aY=
k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE=
k8s.io/apimachinery v0.21.3 h1:3Ju4nvjCngxxMYby0BimUk+pQHPOQp3eCGChk5kfVII=
k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU=
k8s.io/client-go v0.21.3 h1:J9nxZTOmvkInRDCzcSNQmPJbDYN/PjlxXT9Mos3HcLg=
k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU=
k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
k8s.io/component-base v0.21.3 h1:4WuuXY3Npa+iFfi2aDRiOz+anhNvRfye0859ZgfC5Og=
k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 h1:DnzUXII7sVg1FJ/4JX6YDRJfLNAC7idRatPwe07suiI=
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/controller-runtime v0.9.5 h1:WThcFE6cqctTn2jCZprLICO6BaKZfhsT37uAapTNfxc=
sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
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=
k8s.io/api v0.31.10 h1:hR39mlD3fxAMVotfj1aAEUOZhNMf+pL/XpL2zKvfLMk=
k8s.io/api v0.31.10/go.mod h1:UwhlGlhYzRQuDudTdvUZ6bZZAKp0Zs82m+qEw/BZxCU=
k8s.io/apiextensions-apiserver v0.31.10 h1:Scl+8yOqpbO/6eilafV7F1cpjVmobFWu8EJ3Y2TIKt4=
k8s.io/apiextensions-apiserver v0.31.10/go.mod h1:0VbuO1j4eft+aMYjVy0piM+A+aITSvamJwOYRYJyHMw=
k8s.io/apimachinery v0.31.10 h1:fKQxHMu8IFRsC5wsiA7ySL9Z/dw9LOmVs3cifAx1cXk=
k8s.io/apimachinery v0.31.10/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/apiserver v0.31.10 h1:oMK+nnYVh2+D7nujjeEbtBl/kbG9CyqrX06wjkFytdE=
k8s.io/apiserver v0.31.10/go.mod h1:nzEhw+jN3NdDq8b+/uUqL5s4AFRmSkRv5ZJJs8eVuAc=
k8s.io/client-go v0.31.10 h1:2WvGOFKKggxmx6kB6DP1NjdvLPyI6z+CtDWcQsyHpTI=
k8s.io/client-go v0.31.10/go.mod h1:zRlFekIgyvhAEb8osZ6ar1//EqqGgW9C/j5jGVFNMXI=
k8s.io/component-base v0.31.10 h1:8daIQBYMhcnuXMD1otGkjpx4d4b0UIcg18xieLTAGA0=
k8s.io/component-base v0.31.10/go.mod h1:qoSFFg2SO854XgeCJwFL/LPY/oJU1vqJHhNCEgI6xhA=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk=
sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -1,6 +1,6 @@
module backup_restore
go 1.17
go 1.23.8
require (
github.com/oam-dev/kubevela v1.1.8

View File

@ -1,6 +1,6 @@
module tf_validation_backend
go 1.17
go 1.23.8
require github.com/hashicorp/hcl/v2 v2.11.1

View File

@ -1,4 +1,3 @@
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
@ -14,7 +13,6 @@ github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3a
github.com/golang/protobuf v1.1.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.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
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.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
@ -27,7 +25,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
@ -40,7 +37,6 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
@ -57,11 +53,11 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=

55
main.go
View File

@ -17,15 +17,19 @@ limitations under the License.
package main
import (
"flag"
"os"
"time"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/util/feature"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/klog/v2"
"k8s.io/klog/v2/klogr"
"k8s.io/klog/v2/textlogger"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"
terraformv1beta1 "github.com/oam-dev/terraform-controller/api/v1beta1"
"github.com/oam-dev/terraform-controller/api/v1beta2"
@ -52,27 +56,42 @@ func main() {
var namespace string
var controllerNamespace string
flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, "Enable leader election for controller manager, this will ensure there is only one active controller manager.")
flag.DurationVar(&syncPeriod, "informer-re-sync-interval", 10*time.Second, "controller shared informer lister full re-sync period")
flag.StringVar(&metricsAddr, "metrics-addr", ":38080", "The address the metric endpoint binds to.")
flag.StringVar(&namespace, "namespace", "", "Namespace to watch for resources, defaults to all namespaces")
flag.StringVar(&controllerNamespace, "controller-namespace", "", "Namespace to run the terraform jobs")
pflag.BoolVar(&enableLeaderElection, "enable-leader-election", false, "Enable leader election for controller manager, this will ensure there is only one active controller manager.")
pflag.DurationVar(&syncPeriod, "informer-re-sync-interval", 10*time.Second, "controller shared informer lister full re-sync period")
pflag.StringVar(&metricsAddr, "metrics-addr", ":38080", "The address the metric endpoint binds to.")
pflag.StringVar(&namespace, "namespace", "", "Namespace to watch for resources, defaults to all namespaces")
pflag.StringVar(&controllerNamespace, "controller-namespace", "", "Namespace to run the terraform jobs")
feature.DefaultMutableFeatureGate.AddFlag(pflag.CommandLine)
// embed klog
klog.InitFlags(nil)
flag.Parse()
pflag.Parse()
ctrl.SetLogger(klogr.New())
ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig()))
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
LeaderElection: enableLeaderElection,
LeaderElectionID: "ce329a9c.core.oam.dev",
MetricsBindAddress: metricsAddr,
Namespace: namespace,
Port: 9443,
Scheme: scheme,
SyncPeriod: &syncPeriod,
})
// Prepare manager options
mgmOptions := ctrl.Options{
LeaderElection: enableLeaderElection,
LeaderElectionID: "ce329a9c.core.oam.dev",
Metrics: server.Options{
BindAddress: metricsAddr,
},
WebhookServer: webhook.NewServer(webhook.Options{
Port: 9443,
}),
Scheme: scheme,
}
// Only set specific namespace if provided, otherwise watch all namespaces
if namespace != "" {
mgmOptions.Cache = cache.Options{
DefaultNamespaces: map[string]cache.Config{
namespace: {},
},
}
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), mgmOptions)
if err != nil {
setupLog.Error(err, "unable to start manager")
os.Exit(1)