diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 000000000..068829793 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,7 @@ +[allowlist] + description = "Global Allowlist" + + paths = [ + '''test\/openshift\/e2e\/ginkgo\/parallel\/1-005_validate_route_tls_test.go$''', + ] + diff --git a/Makefile b/Makefile index adba3766c..640c61df7 100644 --- a/Makefile +++ b/Makefile @@ -154,15 +154,31 @@ test-gitopsservice-nondefault: test: manifests generate fmt vet ## Run unit tests. go test `go list ./... | grep -v test` -coverprofile cover.out + +.PHONY: e2e-tests-ginkgo +e2e-tests-ginkgo: e2e-tests-sequential-ginkgo e2e-tests-parallel-ginkgo ## Runs kuttl e2e sequential and parallel tests + +.PHONY: e2e-tests-sequential-ginkgo +e2e-tests-sequential-ginkgo: ginkgo ## Runs kuttl e2e sequential tests + @echo "Running GitOps Operator sequential Ginkgo E2E tests..." + $(GINKGO_CLI) -v --trace -r ./test/openshift/e2e/ginkgo/sequential + +.PHONY: e2e-tests-parallel-ginkgo ## Runs kuttl e2e parallel tests, (Defaults to 5 runs at a time) +e2e-tests-parallel-ginkgo: ginkgo + @echo "Running GitOps Operator parallel Ginkgo E2E tests..." + $(GINKGO_CLI) -p --trace -procs=5 --slow-spec-threshold=5m -v -r ./test/openshift/e2e/ginkgo/parallel + .PHONY: e2e-tests-sequential -e2e-tests-sequential: ## Runs kuttl e2e sequentail tests - @echo "Running GitOps Operator sequential E2E tests..." - . ./scripts/run-kuttl-tests.sh sequential +e2e-tests-sequential: + CI=prow make e2e-tests-sequential-ginkgo ## Runs kuttl e2e sequentail tests +# @echo "Running GitOps Operator sequential E2E tests..." +# . ./scripts/run-kuttl-tests.sh sequential .PHONY: e2e-tests-parallel ## Runs kuttl e2e parallel tests, (Defaults to 5 runs at a time) -e2e-tests-parallel: - @echo "Running GitOps Operator parallel E2E tests..." - . ./scripts/run-kuttl-tests.sh parallel +e2e-tests-parallel: + CI=prow make e2e-tests-parallel-ginkgo + # @echo "Running GitOps Operator parallel E2E tests..." + # . ./scripts/run-kuttl-tests.sh parallel .PHONY: e2e-non-olm-tests-sequential e2e-non-olm-tests-sequential: ## Runs kuttl non-olm e2e sequentail tests @@ -258,6 +274,12 @@ KUSTOMIZE = $(shell pwd)/bin/kustomize kustomize: ## Download kustomize locally if necessary. $(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v4@v4.5.2) +GINKGO_CLI = $(shell pwd)/bin/ginkgo +.PHONY: ginkgo +ginkgo: ## Download ginkgo locally if necessary. + $(call go-get-tool,$(GINKGO_CLI),github.com/onsi/ginkgo/v2/ginkgo@v2.1.5) + + # go-get-tool will 'go install' any package $2 and install it to $1. PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST)))) define go-get-tool diff --git a/go.mod b/go.mod index 09c23db52..2e4115df1 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,14 @@ toolchain go1.22.5 require ( github.com/argoproj-labs/argo-rollouts-manager v0.0.6-0.20250314083117-bb5580b286c5 github.com/argoproj-labs/argocd-operator v0.14.0-rc1.0.20250407060436-d8bd8635e78c + github.com/argoproj/argo-cd/v2 v2.12.10 + github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-faf5a4e5c37d github.com/coreos/prometheus-operator v0.40.0 github.com/go-logr/logr v1.4.2 github.com/google/go-cmp v0.6.0 github.com/hashicorp/go-version v1.6.0 - github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.34.0 + github.com/onsi/ginkgo/v2 v2.19.0 + github.com/onsi/gomega v1.34.1 github.com/openshift/api v0.0.0-20240906151052-5d963dce87aa github.com/operator-framework/api v0.17.5 github.com/stretchr/testify v1.10.0 @@ -29,103 +31,188 @@ require ( ) require ( - github.com/argoproj/argo-cd/v2 v2.12.3 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect + dario.cat/mergo v1.0.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v1.1.3 // indirect + github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect + github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect + github.com/bombsimon/logrusr/v2 v2.0.1 // indirect + github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 // indirect github.com/cert-manager/cert-manager v1.14.4 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect + github.com/cloudflare/circl v1.3.7 // indirect + github.com/cyphar/filepath-securejoin v0.3.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/distribution/reference v0.5.0 // indirect github.com/dlclark/regexp2 v1.11.2 // indirect github.com/emicklei/go-restful/v3 v3.11.3 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/fatih/camelcase v1.0.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fvbommel/sortorder v1.1.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.6.1 // indirect + github.com/go-git/go-git/v5 v5.13.1 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/jsonreference v0.20.4 // indirect github.com/go-openapi/swag v0.22.9 // indirect + github.com/go-redis/cache/v9 v9.0.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-github/v53 v53.2.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/imdario/mergo v0.3.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jonboulle/clockwork v0.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.11 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/openshift/client-go v0.0.0-20240215090359-b71f6f2731f5 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc4 // indirect + github.com/openshift/client-go v0.0.0-20200325131901-f7baeb993edb // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.21.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/redis/go-redis/v9 v9.0.5 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sethvargo/go-password v0.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/skeema/knownhosts v1.3.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/vmihailenco/go-tinylfu v0.2.2 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/net v0.33.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.23.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect + google.golang.org/grpc v1.60.1 // indirect google.golang.org/protobuf v1.36.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiserver v0.29.6 // indirect + k8s.io/cli-runtime v0.29.6 // indirect k8s.io/component-base v0.29.6 // indirect + k8s.io/component-helpers v0.29.6 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-aggregator v0.29.6 // indirect k8s.io/kube-openapi v0.0.0-20240227032403-f107216b40e2 // indirect + k8s.io/kubectl v0.29.6 // indirect + k8s.io/kubernetes v1.29.6 // indirect + oras.land/oras-go/v2 v2.3.0 // indirect sigs.k8s.io/gateway-api v1.0.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) +// replace github.com/argoproj-labs/argocd-operator => ../argocd-operator + replace ( - cloud.google.com/go => cloud.google.com/go v0.100.2 - github.com/onsi/ginkgo => github.com/onsi/ginkgo v1.16.4 - github.com/onsi/gomega => github.com/onsi/gomega v1.14.0 - github.com/openshift/client-go => github.com/openshift/client-go v0.0.0-20200325131901-f7baeb993edb - k8s.io/api => k8s.io/api v0.28.3 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.3 - k8s.io/apimachinery => k8s.io/apimachinery v0.28.3 - k8s.io/apiserver => k8s.io/apiserver v0.28.3 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.28.3 - k8s.io/client-go => k8s.io/client-go v0.28.3 // Required by prometheus-operator - k8s.io/cloud-provider => k8s.io/cloud-provider v0.28.3 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.28.3 - k8s.io/code-generator => k8s.io/code-generator v0.28.3 - k8s.io/component-base => k8s.io/component-base v0.28.3 - k8s.io/component-helpers => k8s.io/component-helpers v0.28.3 - k8s.io/controller-manager => k8s.io/controller-manager v0.28.3 - k8s.io/cri-api => k8s.io/cri-api v0.28.3 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.28.3 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.3 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.28.3 - k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.28.3 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.28.3 - k8s.io/kubectl => k8s.io/kubectl v0.28.3 - k8s.io/kubelet => k8s.io/kubelet v0.28.3 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.28.3 - k8s.io/metrics => k8s.io/metrics v0.28.3 - k8s.io/mount-utils => k8s.io/mount-utils v0.28.3 - k8s.io/node-api => k8s.io/node-api v0.28.3 - k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.28.3 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.28.3 - k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.28.3 - k8s.io/sample-controller => k8s.io/sample-controller v0.28.3 + // https://github.com/golang/go/issues/33546#issuecomment-519656923 + github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 + + github.com/go-telegram-bot-api/telegram-bot-api/v5 => github.com/OvyFlash/telegram-bot-api/v5 v5.0.0-20240108230938-63e5c59035bf + + github.com/golang/protobuf => github.com/golang/protobuf v1.5.4 + github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0 + + // Avoid CVE-2022-3064 + gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.4.0 + + // Avoid CVE-2022-28948 + gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 + + k8s.io/api => k8s.io/api v0.29.6 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.29.6 + k8s.io/apimachinery => k8s.io/apimachinery v0.29.6 + k8s.io/apiserver => k8s.io/apiserver v0.29.6 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.29.6 + k8s.io/client-go => k8s.io/client-go v0.29.6 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.29.6 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.29.6 + k8s.io/code-generator => k8s.io/code-generator v0.29.6 + k8s.io/component-base => k8s.io/component-base v0.29.6 + k8s.io/component-helpers => k8s.io/component-helpers v0.29.6 + k8s.io/controller-manager => k8s.io/controller-manager v0.29.6 + k8s.io/cri-api => k8s.io/cri-api v0.29.6 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.29.6 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.29.6 + k8s.io/endpointslice => k8s.io/endpointslice v0.29.6 + k8s.io/kms => k8s.io/kms v0.29.6 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.29.6 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.29.6 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.29.6 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.29.6 + k8s.io/kubectl => k8s.io/kubectl v0.29.6 + k8s.io/kubelet => k8s.io/kubelet v0.29.6 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.29.6 + k8s.io/metrics => k8s.io/metrics v0.29.6 + k8s.io/mount-utils => k8s.io/mount-utils v0.29.6 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.29.6 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.29.6 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.29.6 + k8s.io/sample-controller => k8s.io/sample-controller v0.29.6 ) diff --git a/go.sum b/go.sum index 8fb068b89..6502db672 100644 --- a/go.sum +++ b/go.sum @@ -1,31 +1,84 @@ +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.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +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.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +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 v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/accesscontextmanager v1.8.0/go.mod h1:uI+AI/r1oyWK99NN8cQ3UK76AMelMzgZCvJfsi2c+ps= +cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/aiplatform v1.45.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= +cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/analytics v0.21.2/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= +cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= @@ -34,10 +87,12 @@ cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodC cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= @@ -46,6 +101,7 @@ cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1 cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= @@ -54,29 +110,40 @@ cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAt cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= +cloud.google.com/go/beyondcorp v0.6.1/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= +cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= 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/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= @@ -84,6 +151,8 @@ cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/Zur cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/bigquery v1.52.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= +cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= @@ -91,32 +160,41 @@ cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/cloudbuild v1.10.1/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= +cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= +cloud.google.com/go/cloudtasks v1.11.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= +cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= @@ -131,22 +209,34 @@ cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvj cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= +cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= +cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/container v1.22.1/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= +cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= @@ -155,43 +245,62 @@ cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOX cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/datacatalog v1.14.0/go.mod h1:h0PrGtlihoutNMp/uvwhawLQ9+c63Kz65UFqh49Yo+E= +cloud.google.com/go/datacatalog v1.14.1/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= +cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataplex v1.8.1/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= +cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= +cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= 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/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastore v1.12.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= +cloud.google.com/go/datastore v1.12.1/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= +cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/datastream v1.9.1/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= +cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/deploy v1.11.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= +cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= @@ -200,36 +309,48 @@ cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFM cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dialogflow v1.38.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= +cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/documentai v1.20.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= +cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/eventarc v1.12.1/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= +cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= +cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= @@ -237,28 +358,37 @@ cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5Uwt cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/gkemulticloud v0.6.1/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= +cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= @@ -268,18 +398,24 @@ cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGE cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8= +cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= @@ -287,99 +423,135 @@ cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4 cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/kms v1.11.0/go.mod h1:hwdiYC0xjnWsKQQCQQmIQnS9asjYVSK6jtXm+zFqXLM= +cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= +cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.4.2/go.mod h1:OHrnaYyLUV6oqwh0xiS7e5sLQhP1m0QU9R+WhGDMgIQ= +cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= +cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/metastore v1.11.1/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= +cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/orgpolicy v1.11.0/go.mod h1:2RK748+FtVvnfuynxBzdnyu7sygtoZa1za/0ZfpOs1M= +cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/osconfig v1.12.0/go.mod h1:8f/PaYzoS3JMVfdfTubkowZYGmAhUCjjwnjqWI7NVBc= +cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/policytroubleshooter v1.7.1/go.mod h1:0NaT5v3Ag1M7U5r0GfDCpUFkWd9YqpubBWsQlhanRv0= +cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= +cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= +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/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsub v1.32.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= @@ -388,46 +560,56 @@ cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= @@ -435,12 +617,14 @@ cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= @@ -452,6 +636,8 @@ cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPj cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicedirectory v1.10.1/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= +cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= @@ -463,58 +649,77 @@ cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DR cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= +cloud.google.com/go/speech v1.17.1/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= +cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.3.0/go.mod h1:9IAwXhoyBJ7z9LcAwkj0/7NnPzYaPeZxxVp3zm+5IqA= 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= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.8.1/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= +cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= +cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= @@ -522,31 +727,41 @@ cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vmwareengine v0.4.1/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= +cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= +cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= @@ -557,6 +772,7 @@ github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo github.com/Azure/azure-sdk-for-go v41.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v43.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v11.2.8+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= @@ -584,12 +800,24 @@ github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= 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/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= +github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -608,15 +836,21 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF 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/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= +github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= +github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= @@ -624,14 +858,19 @@ github.com/argoproj-labs/argo-rollouts-manager v0.0.6-0.20250314083117-bb5580b28 github.com/argoproj-labs/argo-rollouts-manager v0.0.6-0.20250314083117-bb5580b286c5/go.mod h1:hX18xfJcnomx/k6urvDp/7+Zwa/y5aF1Mlhz5a2en4k= github.com/argoproj-labs/argocd-operator v0.14.0-rc1.0.20250407060436-d8bd8635e78c h1:rBpU8LkWMK2d3hMYJOSh7U2yESEKGLnaMKyMH4ML/zE= github.com/argoproj-labs/argocd-operator v0.14.0-rc1.0.20250407060436-d8bd8635e78c/go.mod h1:UHe70eXnnCEfzp7EWRofMU+BFnPgZiT5OSqpuInEARA= -github.com/argoproj/argo-cd/v2 v2.12.3 h1:Bi4QahHTnKl3esU5MplQP1wraGhaTpvgAV4GsMqc3Zc= -github.com/argoproj/argo-cd/v2 v2.12.3/go.mod h1:2fh6q4NX/cylbH6Ktx/KjJsX7sOBwF3jbGnO0IZyNOc= +github.com/argoproj/argo-cd/v2 v2.12.10 h1:Qe5cBSnGy0wXAVdMKH69gWZYZ1CwHHxSOdavE4t+sAg= +github.com/argoproj/argo-cd/v2 v2.12.10/go.mod h1:5kppi19e6lVQxlKSd1Cs7LorEZ6rID4nc06YWNHM+rg= +github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-faf5a4e5c37d h1:LrHPuKm4rFfaVzNOqXhuoLNqe7DnhZ3d5pZA+k431Bo= +github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-faf5a4e5c37d/go.mod h1:xMIbuLg9Qj2e0egTy+8NcukbhRaVmWwK9vm3aAQZoi4= +github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 h1:qsHwwOJ21K2Ao0xPju1sNuqphyMnMYkyB3ZLoLtxWpo= +github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1/go.mod h1:CZHlkyAD1/+FbEn6cB2DQTj48IoLGvEYsWEvtzP3238= 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-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -642,6 +881,7 @@ github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.44.289/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -654,19 +894,30 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc= +github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= +github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 h1:IRY7Xy588KylkoycsUhFpW7cdGpy5Y5BPsz4IfuJtGk= +github.com/bradleyfalzon/ghinstallation/v2 v2.6.0/go.mod h1:oQ3etOwN3TRH4EwgW5/7MxSVMGlMlzG/O8TU7eYdoSk= github.com/brancz/kube-rbac-proxy v0.5.0/go.mod h1:cL2VjiIFGS90Cjh5ZZ8+It6tMcBt8rwvuw2J6Mamnl0= +github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -681,6 +932,8 @@ github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= 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= @@ -688,6 +941,10 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -700,6 +957,9 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -720,19 +980,28 @@ github.com/coreos/prometheus-operator v0.40.0/go.mod h1:QOoL5cVI3b1OHgpw8s+pH+Ok github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= +github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.11.2 h1:/u628IuisSTwri5/UKloiIsH8+qF2Pu7xEQX+yIKg68= github.com/dlclark/regexp2 v1.11.2/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -750,10 +1019,15 @@ github.com/elastic/go-sysinfo v1.0.1/go.mod h1:O/D5m1VpYLwGjCYzEt63g3Z1uO3jXfwyz github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= +github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= +github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.11.3 h1:yagOQz/38xJmcNeZJtrUcKjkHRltIaIFXKWeG1SkWGE= github.com/emicklei/go-restful/v3 v3.11.3/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -765,16 +1039,27 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= +github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 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/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= @@ -786,21 +1071,38 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 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/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw= +github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= +github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= +github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= 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-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= 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/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -815,10 +1117,13 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 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/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= @@ -839,6 +1144,7 @@ github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQH github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/errors v0.19.4/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= @@ -847,6 +1153,7 @@ github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34 github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= @@ -869,6 +1176,7 @@ github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhte github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= @@ -884,6 +1192,7 @@ github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6 github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= @@ -901,13 +1210,16 @@ github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7 github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-redis/cache/v9 v9.0.0 h1:0thdtFo0xJi0/WXbRVu8B066z8OvVymXTJGaXrVWnN0= +github.com/go-redis/cache/v9 v9.0.0/go.mod h1:cMwi1N8ASBOufbIvk7cdXe2PbPjK/WMRL95FFHWsSgI= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +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/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -945,11 +1257,13 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= 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= @@ -959,24 +1273,15 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4er 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/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/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -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.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -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.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -986,7 +1291,9 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW 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/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -995,7 +1302,10 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a 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.4.1/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.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/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= @@ -1005,20 +1315,48 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN 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/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= +github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/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-20200417002340-c6e0a841f49a/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= +github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1032,6 +1370,7 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/ github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= @@ -1042,6 +1381,10 @@ github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqE github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= @@ -1057,21 +1400,20 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/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-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= 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.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= -github.com/grpc-ecosystem/grpc-gateway v1.14.4/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0= -github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU= @@ -1117,6 +1459,7 @@ github.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hashicorp/serf v0.9.0/go.mod h1:YL0HO+FifKOW2u1ke99DGVu1zhcpZzNwrLIqBC7vbYU= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -1125,6 +1468,7 @@ github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmcMO9rkaVY= github.com/influxdata/influxdb v1.7.7/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= @@ -1136,17 +1480,23 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= 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/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -1155,6 +1505,7 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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/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/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -1165,7 +1516,10 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -1173,11 +1527,16 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -1202,14 +1561,19 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.0/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lovoo/gcloud-opentracing v0.3.0/go.mod h1:ZFqk2y38kMDDikZPAK7ynTTGuyt17nSPdS3K5e+ZTBY= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -1233,12 +1597,14 @@ github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcME github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -1249,28 +1615,38 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v6 v6.0.49/go.mod h1:qD0lajrGW49lKZLtXKtCB4X/qkMf0a5tBvN2PaZg7Gg= +github.com/minio/minio-go/v7 v7.0.58/go.mod h1:NUDy4A4oXPq1l2yK6LTSvCEzAMeIcoz9lcj5dbzSrRE= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 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/mitchellh/go-wordwrap v1.0.0/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/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 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/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= @@ -1280,6 +1656,7 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq 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 h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= @@ -1288,6 +1665,7 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +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/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= @@ -1298,15 +1676,60 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/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/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= -github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= -github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw= -github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI= -github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= +github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= +github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= +github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +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 v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +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.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= +github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= +github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= +github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= +github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/openshift/api v0.0.0-20200324160301-f91f52aea878/go.mod h1:7k3+uZYOir97walbYUqApHUA2OPhkQpVJHt0n7GJ6P4= github.com/openshift/api v0.0.0-20240906151052-5d963dce87aa h1:RMI6Xa+l8KriyoxsRO/swMDPyCwrxJNA9H67K0Jod/w= github.com/openshift/api v0.0.0-20240906151052-5d963dce87aa/go.mod h1:yimSGmjsI+XF1mr+AKBs2//fSXIOhhetHGbMlBEfXbs= @@ -1328,11 +1751,14 @@ github.com/operator-framework/api v0.17.5/go.mod h1:l/cuwtPxkVUY7fzYgdust2m9tlmb github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= @@ -1342,6 +1768,8 @@ github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1351,6 +1779,7 @@ github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6J github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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= @@ -1430,9 +1859,14 @@ github.com/prometheus/prometheus v1.8.2-0.20200507164740-ecee9c8abfd1/go.mod h1: github.com/prometheus/prometheus v1.8.2-0.20200609102542-5d7e3e970602/go.mod h1:CwaXafRa0mm72de2GQWtfQxjGytbSKIGivWxQvjpRZs= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.0.0-rc.4/go.mod h1:Vo3EsyWnicKnSKCA7HhgnvnyA74wOA69Cd2Meli5mmA= +github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1443,7 +1877,9 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj 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/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= @@ -1459,6 +1895,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU= github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs= github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= @@ -1474,8 +1912,11 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= +github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -1494,7 +1935,10 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 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.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -1509,6 +1953,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ 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/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1520,6 +1967,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -1538,19 +1987,32 @@ github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/vmihailenco/go-tinylfu v0.2.2 h1:H1eiG6HM36iniK6+21n9LLpzx1G9R3DJa2UjUjbynsI= +github.com/vmihailenco/go-tinylfu v0.2.2/go.mod h1:CutYi2Q9puTxfcolkliPq4npPuofg9N9t8JVrjzwa3Q= +github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc= +github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= +github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk= @@ -1559,15 +2021,15 @@ go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4 go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= -go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= -go.etcd.io/etcd/client/v2 v2.305.9/go.mod h1:0NBdNx9wbxtEQLwAQtrDHwx58m02vXpDcgSYI2seohQ= -go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= -go.etcd.io/etcd/pkg/v3 v3.5.9/go.mod h1:BZl0SAShQFk0IpLWR78T/+pyt8AruMHhTNNX73hkNVY= -go.etcd.io/etcd/raft/v3 v3.5.9/go.mod h1:WnFkqzFdZua4LVlVXQEGhmooLeyS7mqzS4Pf4BCVqXg= -go.etcd.io/etcd/server/v3 v3.5.9/go.mod h1:GgI1fQClQCFIzuVjlvdbMxNbnISt90gdfYyqiAIt65g= +go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= +go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= +go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= +go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= +go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -1580,30 +2042,37 @@ 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.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.1/go.mod h1:9NiG9I2aHTKkcxqCILhjtyNA1QEiCjdBACv4IvrFQ+c= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48= go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= -go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= -go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= +go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel v1.18.0/go.mod h1:9lWqYO0Db579XzVuCKFNPDl4s73Voa+zEck3wHaAYQI= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0/go.mod h1:Krqnjl22jUJ0HgMzw5eveuCvFDXY4nSYb4F8t5gdrag= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0/go.mod h1:OfUCyyIiDvNXHWpcWgbF+MWvqPZiNa3YDEnivcnYsV0= -go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= +go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/metric v1.18.0/go.mod h1:nNSpsVDjWGfb7chbRLUNW+PBNdcSTHD4Uu5pfFMOI0k= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= -go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= -go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= -go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM= +go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/trace v1.18.0/go.mod h1:T2+SGJGuYZY3bjj5rgh/hN7KIrlpWC5nS8Mjvzckz+0= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= 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.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1612,7 +2081,6 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -1654,8 +2122,20 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1664,13 +2144,18 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-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-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= 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/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 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= @@ -1689,7 +2174,10 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx 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/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -1698,26 +2186,34 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc 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/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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1735,20 +2231,33 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/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-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/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-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/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-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/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-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -1771,15 +2280,24 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1787,9 +2305,14 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr 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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -1805,7 +2328,9 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1816,6 +2341,7 @@ golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1825,9 +2351,15 @@ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1852,8 +2384,10 @@ golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-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-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1861,30 +2395,44 @@ golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/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-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/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-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/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-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/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-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1892,14 +2440,20 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/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-20210616094352-59db8d763f22/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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1909,17 +2463,19 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1928,11 +2484,20 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= @@ -1940,11 +2505,21 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180805044716-cb6730876b98/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.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= @@ -1958,10 +2533,15 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 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-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1975,6 +2555,7 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1988,6 +2569,7 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/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-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -1997,7 +2579,9 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/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-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190918214516-5a1a30219888/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2009,40 +2593,75 @@ golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtn 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-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200115044656-831fdb1e1868/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-20200227222343-706bc42d1f0d/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-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200422205258-72e4a01eba43/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200603131246-cc40288be839/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/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-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= -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/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= 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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= @@ -2059,17 +2678,37 @@ gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZ gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/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.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= @@ -2078,6 +2717,7 @@ google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRR google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= @@ -2096,6 +2736,11 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= +google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= +google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= +google.golang.org/api v0.125.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2106,6 +2751,7 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID 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-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= @@ -2113,26 +2759,63 @@ google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-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-20200108215221-bd8f9a0ef82f/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-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= @@ -2150,6 +2833,8 @@ google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= @@ -2201,12 +2886,36 @@ google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVix google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= +google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -2217,13 +2926,16 @@ google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= @@ -2249,14 +2961,18 @@ google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= +google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -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= @@ -2269,6 +2985,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -2286,71 +3004,75 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/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-20200603094226-e3079894b1e8/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -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= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM= -k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc= -k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= -k8s.io/apiextensions-apiserver v0.28.3/go.mod h1:NE1XJZ4On0hS11aWWJUTNkmVB03j9LM7gJSisbRt8Lc= -k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A= -k8s.io/apimachinery v0.28.3/go.mod h1:uQTKmIqs+rAYaq+DFaoD2X7pcjLOqbQX2AOiO0nIpb8= -k8s.io/apiserver v0.28.3/go.mod h1:YIpM+9wngNAv8Ctt0rHG4vQuX/I5rvkEMtZtsxW2rNM= -k8s.io/client-go v0.28.3 h1:2OqNb72ZuTZPKCl+4gTKvqao0AMOl9f3o2ijbAj3LI4= -k8s.io/client-go v0.28.3/go.mod h1:LTykbBp9gsA7SwqirlCXBWtK0guzfhpoW4qSm7i9dxo= -k8s.io/code-generator v0.28.3/go.mod h1:A2EAHTRYvCvBrb/MM2zZBNipeCk3f8NtpdNIKawC43M= -k8s.io/component-base v0.28.3 h1:rDy68eHKxq/80RiMb2Ld/tbH8uAE75JdCqJyi6lXMzI= -k8s.io/component-base v0.28.3/go.mod h1:fDJ6vpVNSk6cRo5wmDa6eKIG7UlIQkaFmZN2fYgIUD8= -k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/api v0.29.6 h1:eDxIl8+PeEpwbe2YyS5RXJ9vdn4hnKWMBf4WUJP9DQM= +k8s.io/api v0.29.6/go.mod h1:ZuUPMhJV74DJXapldbg6upaHfiOjrBb+0ffUbBi1jaw= +k8s.io/apiextensions-apiserver v0.29.6 h1:tUu1N6Zt9GT8KVcPF5aGDqfISz1mveM4yFh7eL5bxmE= +k8s.io/apiextensions-apiserver v0.29.6/go.mod h1:iw1EbwZat08I219qrQKoFMHGo7J9KxPqMpVKxCbNbCs= +k8s.io/apimachinery v0.29.6 h1:CLjJ5b0hWW7531n/njRE3rnusw3rhVGCFftPfnG54CI= +k8s.io/apimachinery v0.29.6/go.mod h1:i3FJVwhvSp/6n8Fl4K97PJEP8C+MM+aoDq4+ZJBf70Y= +k8s.io/apiserver v0.29.6 h1:JxgDbpgahOgqoDOf+zVl2mI+rQcHcLQnK6YhhtsjbNs= +k8s.io/apiserver v0.29.6/go.mod h1:HrQwfPWxhwEa+n8/+5YwSF5yT2WXbeyFjqq6KEXHTX8= +k8s.io/cli-runtime v0.29.6 h1:nPbmS6ICW223S0BWTV+sK5xClWe89QB/n16/c5cJwT8= +k8s.io/cli-runtime v0.29.6/go.mod h1:5BzzwnVhtqVJvatDZmSZ6OtiSGqbdn0hKzpRbV3uf5o= +k8s.io/client-go v0.29.6 h1:5E2ebuB/p0F0THuQatyvhDvPL2SIeqwTPrtnrwKob/8= +k8s.io/client-go v0.29.6/go.mod h1:jHZcrQqDplyv20v7eu+iFM4gTpglZSZoMVcKrh8sRGg= +k8s.io/code-generator v0.29.6/go.mod h1:7TYnI0dYItL2cKuhhgPSuF3WED9uMdELgbVXFfn/joE= +k8s.io/component-base v0.29.6 h1:XkVJI67FvBgNb/3kKqvaGKokxUrIR0RrksCPNI+JYCs= +k8s.io/component-base v0.29.6/go.mod h1:kIahZm8aw9lV8Vw17LF89REmeBrv5+QEl3v7HsrmITY= +k8s.io/component-helpers v0.29.6 h1:kG/tK0gXPXj6n3Oxn5Eul8nYzer3SejZI3ClwiWkreQ= +k8s.io/component-helpers v0.29.6/go.mod h1:Ltb44cbXci9fy9rytWwYsu8vHfi4fjyQdSwk6UlCR4E= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.28.3/go.mod h1:kSMjU2tg7vjqqoWVVCcmPmNZ/CofPsoTbSxAipCvZuE= -k8s.io/kube-aggregator v0.28.3 h1:CVbj3+cpshSHR5dWPzLYx3sVpIDEPLlzMSxY/lAc9cM= -k8s.io/kube-aggregator v0.28.3/go.mod h1:5DyLevbRTcWnT1f9b+lB3BfbXC1w7gDa/OtB6kKInCw= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/kms v0.29.6/go.mod h1:vWVImKkJd+1BQY4tBwdfSwjQBiLrnbNtHADcDEDQFtk= +k8s.io/kube-aggregator v0.29.6 h1:jZJjYF58F6kVuGC/kqLfuu7qGHqc2hoVKsDnRj26QRs= +k8s.io/kube-aggregator v0.29.6/go.mod h1:a6z0yORlXVXtGfsVB5PCjh2Soq1S7Wc6fApU6/T2eCE= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/kube-openapi v0.0.0-20240227032403-f107216b40e2 h1:02WBxjyRwX4rJdl3XlWVjFbXT/kAKCsipoM8hQY3Dwo= +k8s.io/kube-openapi v0.0.0-20240227032403-f107216b40e2/go.mod h1:B7Huvd1LKZtTYmY+nC6rnmN8lyGYT9lifBcPD5epL6k= +k8s.io/kubectl v0.29.6 h1:hmkOMyH2uSUV16gIB3Qp2dv09fM2+PGEXz5SH1gwp7Y= +k8s.io/kubectl v0.29.6/go.mod h1:IUpyXy2OCbIMuBMAisDHM9shh5/Nseij4w+HIt0aq6A= +k8s.io/kubernetes v1.29.6 h1:jn8kA/oVOAWZOeoorx6xZ4d+KgGp+Evgi90x9bEI/DE= +k8s.io/kubernetes v1.29.6/go.mod h1:28sDhcb87LX5z3GWAKYmLrhrifxi4W9bEWua4DRTIvk= k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200414100711-2df71ebbae66/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= @@ -2358,12 +3080,17 @@ lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.37.0/go.mod h1:vtL+3mdHx/wcj3iEGz84rQa8vEqR6XM84v5Lcvfph20= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.0.0-20220904174949-82d86e1b6d56/go.mod h1:YSXjPL62P2AMSxBphRHPn7IkzhVHqkvOnRKAKh+W6ZI= modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= +modernc.org/ccgo/v3 v3.16.13-0.20221017192402-261537637ce8/go.mod h1:fUB3Vn0nVPReA+7IG7yZDfjv1TMWjhQP8gCxrFAtL5g= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= @@ -2373,29 +3100,50 @@ modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= +modernc.org/libc v1.17.4/go.mod h1:WNg2ZH56rDEwdropAJeZPQkXmDwh+JCA1s/htl6r2fA= +modernc.org/libc v1.18.0/go.mod h1:vj6zehR5bfc98ipowQOM2nIDUZnVew/wNC/2tOGS+q0= +modernc.org/libc v1.20.3/go.mod h1:ZRfIaEkgrYgZDl6pa4W39HgN5G/yDW+NRmNKZBDFrk0= +modernc.org/libc v1.21.4/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= +modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.3.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= +modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= +modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= +oras.land/oras-go/v2 v2.3.0 h1:lqX1aXdN+DAmDTKjiDyvq85cIaI4RkIKp/PghWlAGIU= +oras.land/oras-go/v2 v2.3.0/go.mod h1:GeAwLuC4G/JpNwkd+bSZ6SkDMGaaYglt6YK2WvZP7uQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0= +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.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= 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/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= 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= diff --git a/test/e2e/argocd_metrics_test.go b/test/e2e/argocd_metrics_test.go index e86fb9dfc..90adbb9bd 100644 --- a/test/e2e/argocd_metrics_test.go +++ b/test/e2e/argocd_metrics_test.go @@ -24,7 +24,7 @@ import ( "time" monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" rbacv1 "k8s.io/api/rbac/v1" diff --git a/test/e2e/argocd_route_test.go b/test/e2e/argocd_route_test.go index 3d71c5575..ba3a8ee75 100644 --- a/test/e2e/argocd_route_test.go +++ b/test/e2e/argocd_route_test.go @@ -21,7 +21,7 @@ import ( "fmt" "strings" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" console "github.com/openshift/api/console/v1" routev1 "github.com/openshift/api/route/v1" diff --git a/test/e2e/gitopsservice_test.go b/test/e2e/gitopsservice_test.go index 9e82930b0..a95ed4669 100644 --- a/test/e2e/gitopsservice_test.go +++ b/test/e2e/gitopsservice_test.go @@ -20,11 +20,12 @@ import ( "context" "crypto/tls" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "os/exec" "path/filepath" + "reflect" "strings" "time" @@ -35,7 +36,7 @@ import ( "github.com/argoproj-labs/argocd-operator/common" "github.com/argoproj-labs/argocd-operator/controllers/argoutil" monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" osappsv1 "github.com/openshift/api/apps/v1" configv1 "github.com/openshift/api/config/v1" @@ -701,7 +702,7 @@ var _ = Describe("GitOpsServiceController", func() { defer response.Body.Close() By("verify reponse") - b, err := ioutil.ReadAll(response.Body) + b, err := io.ReadAll(response.Body) Expect(err).NotTo(HaveOccurred()) m := make(map[string]interface{}) @@ -744,10 +745,14 @@ var _ = Describe("GitOpsServiceController", func() { namespace := argoCDNamespace argocd := &argoapp.ArgoCD{} It("Remove SSO field from Argo CD CR", func() { - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: argoCDInstanceName, Namespace: namespace}, argocd) - argocd.Spec.SSO = nil - err = k8sClient.Update(context.TODO(), argocd) + err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: argoCDInstanceName, Namespace: namespace}, argocd) + Expect(err).ToNot(HaveOccurred()) + + argocd.Spec.SSO = nil + return k8sClient.Update(context.TODO(), argocd) + }) Expect(err).NotTo(HaveOccurred()) }) @@ -800,49 +805,73 @@ var _ = Describe("GitOpsServiceController", func() { gitopsService := &pipelinesv1alpha1.GitopsService{} It("Add runOnInfra spec to gitopsService CR", func() { - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: argoCDNamespace}, gitopsService) - gitopsService.Spec.RunOnInfra = true nodeSelector := argoutil.AppendStringMap(gitopscommon.InfraNodeSelector(), common.DefaultNodeSelector()) - err = k8sClient.Update(context.TODO(), gitopsService) - Expect(err).NotTo(HaveOccurred()) - Eventually(func() error { + err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: argoCDNamespace}, gitopsService) + Expect(err).ToNot(HaveOccurred()) + + gitopsService.Spec.RunOnInfra = true + return k8sClient.Update(context.TODO(), gitopsService) + }) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() bool { deployment := &appsv1.Deployment{} err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: argoCDNamespace}, deployment) - Expect(err).NotTo(HaveOccurred()) - Expect(deployment.Spec.Template.Spec.NodeSelector).To(Equal(nodeSelector)) + if err != nil { + GinkgoWriter.Println("Unable to get Deployment", err) + return false + } + if !reflect.DeepEqual(deployment.Spec.Template.Spec.NodeSelector, nodeSelector) { + return false + } argocd := &argoapp.ArgoCD{} err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: argoCDInstanceName, Namespace: argoCDNamespace}, argocd) - Expect(err).NotTo(HaveOccurred()) - Expect(argocd.Spec.NodePlacement.NodeSelector).To(Equal(gitopscommon.InfraNodeSelector())) - return nil - }, time.Second*180, interval).ShouldNot(HaveOccurred()) + if err != nil { + GinkgoWriter.Println("Unable to get ArgoCD", err) + return false + } + + return reflect.DeepEqual(argocd.Spec.NodePlacement.NodeSelector, gitopscommon.InfraNodeSelector()) + + }, "3m", "5s").Should(BeTrue()) }) It("Remove runOnInfra spec from gitopsService CR", func() { - err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: argoCDNamespace}, gitopsService) - gitopsService.Spec.RunOnInfra = false - err = k8sClient.Update(context.TODO(), gitopsService) - Expect(err).NotTo(HaveOccurred()) - Eventually(func() error { + err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { + err := k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: argoCDNamespace}, gitopsService) + Expect(err).ToNot(HaveOccurred()) + + gitopsService.Spec.RunOnInfra = false + return k8sClient.Update(context.TODO(), gitopsService) + }) + Expect(err).ToNot(HaveOccurred()) + + Eventually(func() bool { deployment := &appsv1.Deployment{} err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: argoCDNamespace}, deployment) - Expect(err).NotTo(HaveOccurred()) + if err != nil { + GinkgoWriter.Println("Unable to get Deployment", err) + return false + } + if len(deployment.Spec.Template.Spec.NodeSelector) != 1 { - return fmt.Errorf("expected one nodeSelector in deployment") + GinkgoWriter.Println("expected one nodeSelector in deployment") + return false } argocd := &argoapp.ArgoCD{} err = k8sClient.Get(context.TODO(), types.NamespacedName{Name: argoCDInstanceName, Namespace: argoCDNamespace}, argocd) - Expect(err).NotTo(HaveOccurred()) - if argocd.Spec.NodePlacement != nil { - return fmt.Errorf("expected no NodePlacement in argocd ") + if err != nil { + GinkgoWriter.Println("Unable to get ArgoCD", err) + return false } - return nil - }, time.Second*180, interval).ShouldNot(HaveOccurred()) + return argocd.Spec.NodePlacement == nil + }, "3m", "5s").Should(BeTrue()) }) }) @@ -886,7 +915,7 @@ func getAccessToken(user, pass, accessURL string) (string, error) { } defer res.Body.Close() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { return "", err } diff --git a/test/e2e/suite_test.go b/test/e2e/suite_test.go index 4b5b95a43..6dc8e2c69 100644 --- a/test/e2e/suite_test.go +++ b/test/e2e/suite_test.go @@ -29,7 +29,7 @@ import ( argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" argocdprovisioner "github.com/argoproj-labs/argocd-operator/controllers/argocd" monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "github.com/openshift/api/apps/v1" configv1 "github.com/openshift/api/config/v1" @@ -175,7 +175,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) }() -}, 60) +}) var _ = AfterSuite(func() { By("remove the GitOpsService Instance") diff --git a/test/helper/application_status.go b/test/helper/application_status.go index 364f62d4c..8526ea15b 100644 --- a/test/helper/application_status.go +++ b/test/helper/application_status.go @@ -26,7 +26,7 @@ import ( "time" argoapp "github.com/argoproj-labs/argocd-operator/api/v1beta1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" corev1 "k8s.io/api/core/v1" kubeerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/nondefaulte2e/gitops_service_nondefault_test.go b/test/nondefaulte2e/gitops_service_nondefault_test.go index 232be14ef..eb1eb3398 100644 --- a/test/nondefaulte2e/gitops_service_nondefault_test.go +++ b/test/nondefaulte2e/gitops_service_nondefault_test.go @@ -22,7 +22,7 @@ import ( "time" argoapp "github.com/argoproj-labs/argocd-operator/api/v1beta1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" diff --git a/test/nondefaulte2e/suite_test.go b/test/nondefaulte2e/suite_test.go index d749cccd2..3ff935c84 100644 --- a/test/nondefaulte2e/suite_test.go +++ b/test/nondefaulte2e/suite_test.go @@ -30,7 +30,7 @@ import ( argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" argocdprovisioner "github.com/argoproj-labs/argocd-operator/controllers/argocd" monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" appsv1 "github.com/openshift/api/apps/v1" configv1 "github.com/openshift/api/config/v1" @@ -159,7 +159,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) }() -}, 60) +}) var _ = AfterSuite(func() { By("remove the GitOpsService Instance") diff --git a/test/openshift/e2e/ginkgo/fixture/application/fixture.go b/test/openshift/e2e/ginkgo/fixture/application/fixture.go new file mode 100644 index 000000000..564b74766 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/application/fixture.go @@ -0,0 +1,124 @@ +package application + +import ( + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + "k8s.io/client-go/util/retry" + + appv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + "github.com/argoproj/gitops-engine/pkg/sync/common" + matcher "github.com/onsi/gomega/types" + + . "github.com/onsi/ginkgo/v2" + + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func expectedCondition(f func(app *appv1alpha1.Application) bool) matcher.GomegaMatcher { + + return WithTransform(func(app *appv1alpha1.Application) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(app), app) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(app) + + }, BeTrue()) + +} + +func HaveOperationStatePhase(expectedPhase common.OperationPhase) matcher.GomegaMatcher { + + return expectedCondition(func(app *appv1alpha1.Application) bool { + + var currStatePhase string + + if app.Status.OperationState != nil { + currStatePhase = string(app.Status.OperationState.Phase) + } + + GinkgoWriter.Println("HaveOperationStatePhase - current phase:", currStatePhase, " / expected phase:", expectedPhase) + + return currStatePhase == string(expectedPhase) + + }) + +} + +func HaveHealthStatusCode(expectedHealth health.HealthStatusCode) matcher.GomegaMatcher { + + return expectedCondition(func(app *appv1alpha1.Application) bool { + + GinkgoWriter.Println("HaveHealthStatusCode - current health:", app.Status.Health.Status, " / expected health:", expectedHealth) + + return app.Status.Health.Status == expectedHealth + + }) + +} + +// HaveSyncStatusCode waits for Argo CD to have the given sync status +func HaveSyncStatusCode(expected appv1alpha1.SyncStatusCode) matcher.GomegaMatcher { + + return expectedCondition(func(app *appv1alpha1.Application) bool { + + GinkgoWriter.Println("HaveSyncStatusCode - current syncStatusCode:", app.Status.Sync.Status, " / expected syncStatusCode:", expected) + + return app.Status.Sync.Status == expected + + }) + +} + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *appv1alpha1.Application, modify func(*appv1alpha1.Application)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) + +} + +// Update will keep trying to update object until it succeeds, or times out. +func UpdateWithError(obj *appv1alpha1.Application, modify func(*appv1alpha1.Application)) error { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + + return err +} diff --git a/test/openshift/e2e/ginkgo/fixture/argocd/fixture.go b/test/openshift/e2e/ginkgo/fixture/argocd/fixture.go new file mode 100644 index 000000000..e8d89812a --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/argocd/fixture.go @@ -0,0 +1,209 @@ +package argocd + +import ( + "context" + "fmt" + "os/exec" + "strings" + "time" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + matcher "github.com/onsi/gomega/types" + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Update will update an ArgoCD CR. Update will keep trying to update object until it succeeds, or times out. +func Update(obj *argov1beta1api.ArgoCD, modify func(*argov1beta1api.ArgoCD)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) + + // After we update ArgoCD CR, we should wait a few moments for the operator to reconcile the change. + // - Ideally, the ArgoCD CR would have a .status field that we could read, that would indicate which resource version/generation had been reconciled. + // - Sadly, this does not exist, so we instead must use time.Sleep() (for now) + time.Sleep(5 * time.Second) +} + +func GetOpenShiftGitOpsNSArgoCD() (*argov1beta1api.ArgoCD, error) { + + k8sClient, _ := utils.GetE2ETestKubeClient() + + argoCD := argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops", Namespace: "openshift-gitops"}, + } + + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(&argoCD), &argoCD) + + return &argoCD, err + +} + +// BeAvailable waits for Argo CD instance to have .status.phase of 'Available' +func BeAvailable() matcher.GomegaMatcher { + return BeAvailableWithCustomSleepTime(10 * time.Second) +} + +// In most cases, you should probably just use 'BeAvailable'. +func BeAvailableWithCustomSleepTime(sleepTime time.Duration) matcher.GomegaMatcher { + + // Wait X seconds to allow operator to reconcile the ArgoCD CR, before we start checking if it's ready + // - We do this so that any previous calls to update the ArgoCD CR have been reconciled by the operator, before we wait to see if ArgoCD has become available. + // - I'm not aware of a way to do this without a sleep statement, but when we have something better we should do that instead. + time.Sleep(sleepTime) + + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + + if argocd.Status.Phase != "Available" { + GinkgoWriter.Println("ArgoCD status is not yet Available") + return false + } + GinkgoWriter.Println("ArgoCD status is now", argocd.Status.Phase) + + return true + }) +} + +func HavePhase(phase string) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + GinkgoWriter.Println("HavePhase:", "expected:", phase, "actual:", argocd.Status.Phase) + return argocd.Status.Phase == phase + }) +} + +func HaveRedisStatus(status string) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + GinkgoWriter.Println("HaveRedisStatus:", "expected:", status, "actual:", argocd.Status.Redis) + return argocd.Status.Redis == status + }) +} + +func HaveServerStatus(status string) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + GinkgoWriter.Println("HaveServerStatus:", "expected:", status, "actual:", argocd.Status.Server) + return argocd.Status.Server == status + }) +} + +func HaveApplicationSetControllerStatus(status string) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + GinkgoWriter.Println("HaveApplicationSetControllerStatus:", "expected:", status, "actual:", argocd.Status.ApplicationSetController) + return argocd.Status.ApplicationSetController == status + }) +} + +func HaveNotificationControllerStatus(status string) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + GinkgoWriter.Println("HaveNotificationControllerStatus:", "expected:", status, "actual:", argocd.Status.NotificationsController) + return argocd.Status.NotificationsController == status + }) +} + +func HaveSSOStatus(status string) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + GinkgoWriter.Println("HaveSSOStatus:", "expected:", status, "actual:", argocd.Status.SSO) + return argocd.Status.SSO == status + }) +} + +func HaveHost(host string) matcher.GomegaMatcher { + return fetchArgoCD(func(argocd *argov1beta1api.ArgoCD) bool { + GinkgoWriter.Println("HaveHost:", "expected:", host, "actual:", argocd.Status.Host) + return argocd.Status.Host == host + }) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchArgoCD(f func(*argov1beta1api.ArgoCD) bool) matcher.GomegaMatcher { + + return WithTransform(func(argocd *argov1beta1api.ArgoCD) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(argocd), argocd) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(argocd) + + }, BeTrue()) + +} + +func LogInToDefaultArgoCDInstance() error { + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + return err + } + + var routeList routev1.RouteList + Expect(k8sClient.List(context.Background(), &routeList, client.InNamespace("openshift-gitops"))).To(Succeed()) + + var route *routev1.Route + for idx := range routeList.Items { + idxRoute := routeList.Items[idx] + + if idxRoute.Name == "openshift-gitops-server" { + route = &idxRoute + } + } + if route == nil { + return fmt.Errorf("unable to locate route") + } + + secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-cluster", Namespace: "openshift-gitops"}} + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(secret), secret); err != nil { + return fmt.Errorf("unable to locate 'openshift-gitops-cluster' Secret") + } + + // Note: '--skip-test-tls' parameter was added in Feb 2025, to work around OpenShift Routes not supporting HTTP2 by default, along with Argo CD upstream bugs https://github.com/argoproj/argo-cd/issues/21764, and https://github.com/argoproj/argo-cd/issues/20121 + output, err := RunArgoCDCLI("login", route.Spec.Host, "--username", "admin", "--password", string(secret.Data["admin.password"]), "--insecure", "--skip-test-tls") + if err != nil { + return err + } + + if !strings.Contains(string(output), "'admin:login' logged in successfully") { + return fmt.Errorf("unable to log in to Argo CD") + } + + return nil + +} + +func RunArgoCDCLI(args ...string) (string, error) { + + cmdArgs := append([]string{"argocd"}, args...) + + GinkgoWriter.Println("executing command", cmdArgs) + + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + + output, err := cmd.CombinedOutput() + GinkgoWriter.Println(string(output)) + + return string(output), err +} diff --git a/test/openshift/e2e/ginkgo/fixture/clusterserviceversion/fixture.go b/test/openshift/e2e/ginkgo/fixture/clusterserviceversion/fixture.go new file mode 100644 index 000000000..867a26279 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/clusterserviceversion/fixture.go @@ -0,0 +1,31 @@ +package clusterserviceversion + +import ( + "context" + + . "github.com/onsi/gomega" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Update will update a ClusterServiceVersion CR. Update will keep trying to update object until it succeeds, or times out. +func Update(obj *olmv1alpha1.ClusterServiceVersion, modify func(*olmv1alpha1.ClusterServiceVersion)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/configmap/fixture.go b/test/openshift/e2e/ginkgo/fixture/configmap/fixture.go new file mode 100644 index 000000000..b06d964ee --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/configmap/fixture.go @@ -0,0 +1,97 @@ +package configmap + +import ( + "context" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *corev1.ConfigMap, modify func(*corev1.ConfigMap)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) +} + +// HaveStringDataKeyValue returns true if ConfigMap has 'key' field under .data map, and the value of that field is equal to 'value' +func HaveStringDataKeyValue(key string, value string) matcher.GomegaMatcher { + return fetchConfigMap(func(cm *corev1.ConfigMap) bool { + a, exists := cm.Data[key] + if !exists { + GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMap key", key, "does not exist.") + return false + } + + // Remove leading and trailing whitespace + a = strings.TrimSpace(a) + value = strings.TrimSpace(value) + + if strings.Contains(value, "\n") { + GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMag key", key) + GinkgoWriter.Println("Value:") + GinkgoWriter.Println("|" + a + "|") + GinkgoWriter.Println("Expected:") + GinkgoWriter.Println("|" + value + "|") + } else { + GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMag key", key, "Value:", a, "Expected:", value) + } + + return string(a) == value + }) + +} + +// HaveStringDataKeyValue returns true if ConfigMap has 'key' field under .data map, and the value of that field is equal to 'value' +func HaveNonEmptyDataKey(key string) matcher.GomegaMatcher { + return fetchConfigMap(func(cm *corev1.ConfigMap) bool { + a, exists := cm.Data[key] + if !exists { + GinkgoWriter.Println("HaveStringDataKeyValue: ConfigMap key", key, "does not exist.") + return false + } + return len(strings.TrimSpace(a)) > 0 + }) + +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchConfigMap(f func(*corev1.ConfigMap) bool) matcher.GomegaMatcher { + + return WithTransform(func(configMap *corev1.ConfigMap) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(configMap), configMap) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(configMap) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go new file mode 100644 index 000000000..fc240b876 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/deployment/fixture.go @@ -0,0 +1,317 @@ +package deployment + +import ( + "context" + "reflect" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + "sigs.k8s.io/controller-runtime/pkg/client" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" +) + +func GetEnv(d *appsv1.Deployment, key string) (*string, error) { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + return nil, err + } + + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(d), d); err != nil { + return nil, err + } + + containers := d.Spec.Template.Spec.Containers + + Expect(len(containers)).Should(BeNumerically("==", 1)) + + for idx := range containers[0].Env { + + currEnv := containers[0].Env[idx] + + if currEnv.Name == key { + return &currEnv.Name, nil + } + } + + return nil, nil + +} + +func SetEnv(depl *appsv1.Deployment, key string, value string) { + + Update(depl, func(d *appsv1.Deployment) { + containers := d.Spec.Template.Spec.Containers + + Expect(len(containers)).Should(BeNumerically("==", 1)) + + newEnvVars := []corev1.EnvVar{} + + match := false + for idx := range containers[0].Env { + + currEnv := containers[0].Env[idx] + + if currEnv.Name == key { + // replace with the value from the param + newEnvVars = append(newEnvVars, corev1.EnvVar{Name: key, Value: value}) + match = true + } else { + newEnvVars = append(newEnvVars, currEnv) + } + } + + if !match { + newEnvVars = append(newEnvVars, corev1.EnvVar{Name: key, Value: value}) + } + + containers[0].Env = newEnvVars + + }) + +} + +func RemoveEnv(depl *appsv1.Deployment, key string) { + + Update(depl, func(d *appsv1.Deployment) { + containers := d.Spec.Template.Spec.Containers + + Expect(len(containers)).Should(BeNumerically("==", 1)) + + newEnvVars := []corev1.EnvVar{} + + for idx := range containers[0].Env { + + currEnv := containers[0].Env[idx] + + if currEnv.Name == key { + // don't add, thus causing it to be removed + } else { + newEnvVars = append(newEnvVars, currEnv) + } + } + + containers[0].Env = newEnvVars + + }) + +} + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *appsv1.Deployment, modify func(*appsv1.Deployment)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) +} + +func GetTemplateSpecInitContainerByName(name string, depl appsv1.Deployment) *corev1.Container { + + for idx := range depl.Spec.Template.Spec.InitContainers { + + container := depl.Spec.Template.Spec.InitContainers[idx] + if container.Name == name { + return &container + } + } + + return nil +} + +func GetTemplateSpecContainerByName(name string, depl appsv1.Deployment) *corev1.Container { + + for idx := range depl.Spec.Template.Spec.Containers { + + container := depl.Spec.Template.Spec.Containers[idx] + if container.Name == name { + return &container + } + } + + return nil +} + +func HaveTemplateSpecNodeSelector(nodeSelector map[string]string) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + + templateSpec := depl.Spec.Template.Spec + + if templateSpec.NodeSelector == nil { + GinkgoWriter.Println("HaveTemplateSpecNodeSelector - .spec.template.spec is nil") + return false + } + + GinkgoWriter.Println("HaveTemplateSpecNodeSelector - expected:", nodeSelector, "actual:", templateSpec.NodeSelector) + return reflect.DeepEqual(nodeSelector, templateSpec.NodeSelector) + }) + +} + +func HaveTolerations(tolerations []corev1.Toleration) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + + templateSpec := depl.Spec.Template.Spec + + GinkgoWriter.Println("HaveTolerations - expected:", tolerations, "actual:", templateSpec.Tolerations) + + return reflect.DeepEqual(templateSpec.Tolerations, tolerations) + }) + +} + +func HaveObservedGeneration(observedGeneration int) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + GinkgoWriter.Println("Deployment HaveObservedGeneration:", "expected: ", observedGeneration, "actual: ", depl.Status.ObservedGeneration) + return int64(observedGeneration) == depl.Status.ObservedGeneration + }) +} + +func HaveReplicas(replicas int) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + GinkgoWriter.Println("Deployment", depl.Name, "- HaveReplicas:", "expected: ", replicas, "actual: ", depl.Status.Replicas) + return depl.Status.Replicas == int32(replicas) && depl.Generation == depl.Status.ObservedGeneration + }) +} + +func HaveReadyReplicas(readyReplicas int) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + GinkgoWriter.Println("Deployment ", depl.Name, "- HaveReadyReplicas:", "expected: ", readyReplicas, "actual: ", depl.Status.ReadyReplicas) + return depl.Status.ReadyReplicas == int32(readyReplicas) && depl.Generation == depl.Status.ObservedGeneration + }) +} + +func HaveUpdatedReplicas(updatedReplicas int) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + GinkgoWriter.Println("Deployment HaveUpdatedReplicas:", "expected: ", updatedReplicas, "actual: ", depl.Status.UpdatedReplicas) + return depl.Status.UpdatedReplicas == int32(updatedReplicas) && depl.Generation == depl.Status.ObservedGeneration + }) +} + +func HaveAvailableReplicas(availableReplicas int) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + GinkgoWriter.Println("Deployment HaveAvailableReplicas:", "expected: ", availableReplicas, "actual: ", depl.Status.AvailableReplicas) + return depl.Status.AvailableReplicas == int32(availableReplicas) && depl.Generation == depl.Status.ObservedGeneration + }) +} + +func HaveContainerCommandSubstring(expectedCommandSubstring string, containerIndex int) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + + containers := depl.Spec.Template.Spec.Containers + + if len(containers) <= containerIndex { + GinkgoWriter.Println("current container slice has length", len(containers), "index is", containerIndex) + return false + } + + // Combine Command and Args, adding spaces (' ') between the args + var cmdLine string + + for _, val := range containers[containerIndex].Command { + if val == "" { + cmdLine += "\"\"" + " " + } else { + cmdLine += val + " " + } + } + cmdLine = strings.TrimSpace(cmdLine) + + for _, val := range containers[containerIndex].Args { + if val == "" { + cmdLine += "\"\"" + " " + } else { + cmdLine += val + " " + } + } + cmdLine = strings.TrimSpace(cmdLine) + + GinkgoWriter.Println("HaveContainerCommandSubstring: Have:") + GinkgoWriter.Println(cmdLine) + GinkgoWriter.Println("HaveContainerCommandSubstring: Expect:") + GinkgoWriter.Println(expectedCommandSubstring) + + return strings.Contains(cmdLine, expectedCommandSubstring) + + }) +} + +func HaveContainerWithEnvVar(envKey string, envValue string, containerIndex int) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + + containers := depl.Spec.Template.Spec.Containers + + if len(containers) <= containerIndex { + GinkgoWriter.Println("current container slice has length", len(containers), "index is", containerIndex) + return false + } + + container := containers[containerIndex] + + for _, env := range container.Env { + if env.Name == envKey { + GinkgoWriter.Println("HaveContainerWithEnvVar - Key ", envKey, " Expected:", envValue, "Actual:", env.Value) + if env.Value == envValue { + return true + } + } + } + + return false + }) +} + +func HaveConditionTypeStatus(expectedConditionType appsv1.DeploymentConditionType, expectedConditionStatus corev1.ConditionStatus) matcher.GomegaMatcher { + return fetchDeployment(func(depl *appsv1.Deployment) bool { + + GinkgoWriter.Println("Conditions:") + for _, condition := range depl.Status.Conditions { + GinkgoWriter.Println("-", condition.Type, condition.Status) + if condition.Type == expectedConditionType && condition.Status == expectedConditionStatus { + return true + } + } + + return false + }) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchDeployment(f func(*appsv1.Deployment) bool) matcher.GomegaMatcher { + + return WithTransform(func(depl *appsv1.Deployment) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(depl), depl) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(depl) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/deploymentconfig/fixture.go b/test/openshift/e2e/ginkgo/fixture/deploymentconfig/fixture.go new file mode 100644 index 000000000..c889fac97 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/deploymentconfig/fixture.go @@ -0,0 +1,51 @@ +package deploymentconfig + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + "sigs.k8s.io/controller-runtime/pkg/client" + + openshiftappsv1 "github.com/openshift/api/apps/v1" +) + +func HaveReplicas(replicas int) matcher.GomegaMatcher { + return fetchDeploymentConfig(func(depl *openshiftappsv1.DeploymentConfig) bool { + GinkgoWriter.Println("DeploymentConfig - HaveReplicas:", "expected: ", replicas, "actual: ", depl.Status.Replicas) + return depl.Status.Replicas == int32(replicas) && depl.Generation == depl.Status.ObservedGeneration + }) +} + +func HaveReadyReplicas(readyReplicas int) matcher.GomegaMatcher { + return fetchDeploymentConfig(func(depl *openshiftappsv1.DeploymentConfig) bool { + GinkgoWriter.Println("DeploymentConfig - HaveReadyReplicas:", "expected: ", readyReplicas, "actual: ", depl.Status.ReadyReplicas) + return depl.Status.ReadyReplicas == int32(readyReplicas) && depl.Generation == depl.Status.ObservedGeneration + }) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchDeploymentConfig(f func(*openshiftappsv1.DeploymentConfig) bool) matcher.GomegaMatcher { + + return WithTransform(func(depl *openshiftappsv1.DeploymentConfig) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(depl), depl) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(depl) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/fixture.go b/test/openshift/e2e/ginkgo/fixture/fixture.go new file mode 100644 index 000000000..c58f758bc --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/fixture.go @@ -0,0 +1,775 @@ +package fixture + +import ( + "context" + "fmt" + "os" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + routev1 "github.com/openshift/api/route/v1" + securityv1 "github.com/openshift/api/security/v1" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/retry" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + + rolloutmanagerv1alpha1 "github.com/argoproj-labs/argo-rollouts-manager/api/v1alpha1" + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + + "github.com/onsi/gomega/format" + gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + subscriptionFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/subscription" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apierr "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + LabelsKey = "app" + LabelsValue = "test-argo-app" +) + +var NamespaceLabels = map[string]string{LabelsKey: LabelsValue} + +func EnsureParallelCleanSlate() { + + // Increase the maximum length of debug output, for when tests fail + format.MaxLength = 16 * 1024 + SetDefaultEventuallyTimeout(time.Second * 30) + SetDefaultEventuallyPollingInterval(time.Second * 3) + SetDefaultConsistentlyDuration(time.Second * 10) + SetDefaultConsistentlyPollingInterval(time.Second * 1) + + k8sClient, _ := utils.GetE2ETestKubeClient() + + // Finally, wait for default openshift-gitops instance to be ready + // - Parallel tests should not write to any resources in 'openshift-gitops' namespace (sequential only), but they are allowed to read from them. + defaultOpenShiftGitOpsArgoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops", Namespace: "openshift-gitops"}, + } + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(defaultOpenShiftGitOpsArgoCD), defaultOpenShiftGitOpsArgoCD) + Expect(err).ToNot(HaveOccurred()) + + Eventually(defaultOpenShiftGitOpsArgoCD, "5m", "5s").Should(argocd.BeAvailableWithCustomSleepTime(3 * time.Second)) + + // Unlike sequential clean slate, parallel clean slate cannot assume that there are no other tests running. This limits our ability to clean up old test artifacts. +} + +// EnsureSequentialCleanSlate will clean up resources that were created during previous sequential tests +// - Deletes namespaces that were created by previous tests +// - Deletes other cluster-scoped resources that were created +// - Reverts changes made to Subscription CR +// - etc +func EnsureSequentialCleanSlate() { + Expect(EnsureSequentialCleanSlateWithError()).To(Succeed()) +} + +func EnsureSequentialCleanSlateWithError() error { + + // With sequential tests, we are always safe to assume that there is no other test running. That allows us to clean up old test artifacts before new test starts. + + // Increase the maximum length of debug output, for when tests fail + format.MaxLength = 16 * 1024 + SetDefaultEventuallyTimeout(time.Second * 30) + SetDefaultEventuallyPollingInterval(time.Second * 3) + SetDefaultConsistentlyDuration(time.Second * 10) + SetDefaultConsistentlyPollingInterval(time.Second * 1) + + ctx := context.Background() + k8sClient, _ := utils.GetE2ETestKubeClient() + + // If the CSV in 'openshift-gitops-operator' NS exists, make sure the CSV does not contain the dynamic plugin env var + if err := RemoveDynamicPluginFromCSV(ctx, k8sClient); err != nil { + return err + } + + if err := RestoreSubcriptionToDefault(); err != nil { + return err + } + + // ensure namespaces created during test are deleted + err := ensureTestNamespacesDeleted(ctx, k8sClient) + if err != nil { + return err + } + + defaultOpenShiftGitOpsArgoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops", Namespace: "openshift-gitops"}, + } + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(defaultOpenShiftGitOpsArgoCD), defaultOpenShiftGitOpsArgoCD); err != nil { + return err + } + // Ensure that default state of ArgoCD CR in openshift-gitops is restored + if err := updateWithoutConflict(defaultOpenShiftGitOpsArgoCD, func(obj client.Object) { + argocdObj, ok := obj.(*argov1beta1api.ArgoCD) + Expect(ok).To(BeTrue()) + + // HA should be disabled by default + argocdObj.Spec.HA.Enabled = false + + // .spec.monitoring.disableMetrics should be nil by default + argocdObj.Spec.Monitoring.DisableMetrics = nil + + // Ensure that api server route has not been disabled, nor exposed via different settings + argocdObj.Spec.Server.Route = argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + TLS: &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect, + }, + } + + }); err != nil { + return err + } + + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + } + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(gitopsService), gitopsService); err != nil { + return err + } + + // Ensure that run on infra is disabled: some tests will enable it + if err := updateWithoutConflict(gitopsService, func(obj client.Object) { + goObj, ok := obj.(*gitopsoperatorv1alpha1.GitopsService) + Expect(ok).To(BeTrue()) + + goObj.Spec.NodeSelector = nil + goObj.Spec.RunOnInfra = false + goObj.Spec.Tolerations = nil + }); err != nil { + return err + } + + // Clean up old cluster-scoped role from 1-034 + _ = k8sClient.Delete(ctx, &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "custom-argocd-role"}}) + + // Delete all existing RolloutManagers in openshift-gitops Namespace + var rolloutManagerList rolloutmanagerv1alpha1.RolloutManagerList + if err := k8sClient.List(ctx, &rolloutManagerList, client.InNamespace("openshift-gitops")); err != nil { + return err + } + for _, rm := range rolloutManagerList.Items { + if err := k8sClient.Delete(ctx, &rm); err != nil { + return err + } + } + + // Delete 'restricted-dropcaps' which is created by at least one test + scc := &securityv1.SecurityContextConstraints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restricted-dropcaps", + }, + } + if err := k8sClient.Delete(ctx, scc); err != nil { + if !apierr.IsNotFound(err) { + return err + } + // Otherwise, expected error if it doesn't exist. + } + + // Finally, wait for default openshift-gitops instance to be ready + Eventually(defaultOpenShiftGitOpsArgoCD, "5m", "5s").Should(argocd.BeAvailable()) + + return nil +} + +// RemoveDynamicPluginFromCSV ensures that if the CSV in 'openshift-gitops-operator' NS exists, that the CSV does not contain the dynamic plugin env var +func RemoveDynamicPluginFromCSV(ctx context.Context, k8sClient client.Client) error { + + if EnvNonOLM() || EnvLocalRun() { + // Skipping as CSV does exist when not using OLM, nor does it exist when running locally + return nil + } + + var csv *olmv1alpha1.ClusterServiceVersion + var csvList olmv1alpha1.ClusterServiceVersionList + Expect(k8sClient.List(ctx, &csvList, client.InNamespace("openshift-gitops-operator"))).To(Succeed()) + + for idx := range csvList.Items { + idxCSV := csvList.Items[idx] + if strings.Contains(idxCSV.Name, "gitops-operator") { + csv = &idxCSV + break + } + } + Expect(csv).ToNot(BeNil()) + + if err := updateWithoutConflict(csv, func(obj client.Object) { + + csvObj, ok := obj.(*olmv1alpha1.ClusterServiceVersion) + Expect(ok).To(BeTrue()) + + envList := csvObj.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Env + + newEnvList := []corev1.EnvVar{} + for idx := range envList { + idxEnv := envList[idx] + if idxEnv.Name == "DYNAMIC_PLUGIN_START_OCP_VERSION" { + continue + } else { + newEnvList = append(newEnvList, idxEnv) + } + } + csvObj.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Env = newEnvList + + }); err != nil { + return err + } + return nil +} + +func CreateRandomE2ETestNamespace() corev1.Namespace { + + randomVal := string(uuid.NewUUID()) + randomVal = randomVal[0:13] // Only use 14 characters of randomness. If we use more, then we start to hit limits on parts of code which limit # of characters to 63 + + testNamespaceName := "gitops-e2e-test-" + randomVal + + ns := CreateNamespace(string(testNamespaceName)) + return ns +} + +func CreateRandomE2ETestNamespaceWithCleanupFunc() (corev1.Namespace, func()) { + + ns := CreateRandomE2ETestNamespace() + return ns, nsDeletionFunc(&ns) +} + +// Create namespace for tests having a specific label for identification +// - If the namespace already exists, it will be deleted first +func CreateNamespace(name string) corev1.Namespace { + + k8sClient, _ := utils.GetE2ETestKubeClient() + + ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: name}} + // If the Namespace already exists, delete it first + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(ns), ns); err == nil { + // Namespace exists, so delete it first + Expect(deleteNamespace(context.Background(), ns.Name, k8sClient)).To(Succeed()) + } + + ns = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: NamespaceLabels, + }} + + err := k8sClient.Create(context.Background(), ns) + Expect(err).ToNot(HaveOccurred()) + + return *ns +} + +func CreateNamespaceWithCleanupFunc(name string) (corev1.Namespace, func()) { + + ns := CreateNamespace(name) + return ns, nsDeletionFunc(&ns) +} + +// Create a namespace 'name' that is managed by another namespace 'managedByNamespace', via managed-by label. +func CreateManagedNamespace(name string, managedByNamespace string) corev1.Namespace { + k8sClient, _ := utils.GetE2ETestKubeClient() + + ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: name}} + + // If the Namespace already exists, delete it first + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(ns), ns); err == nil { + // Namespace exists, so delete it first + Expect(deleteNamespace(context.Background(), ns.Name, k8sClient)).To(Succeed()) + } + + ns = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{ + Name: name, + Labels: map[string]string{ + LabelsKey: LabelsValue, + "argocd.argoproj.io/managed-by": managedByNamespace, + }, + }} + + Expect(k8sClient.Create(context.Background(), ns)).To(Succeed()) + + return *ns + +} + +func CreateManagedNamespaceWithCleanupFunc(name string, managedByNamespace string) (corev1.Namespace, func()) { + ns := CreateManagedNamespace(name, managedByNamespace) + return ns, nsDeletionFunc(&ns) +} + +// nsDeletionFunc is a convenience function that returns a function that deletes a namespace. This is used for Namespace cleanup by other functions. +func nsDeletionFunc(ns *corev1.Namespace) func() { + + return func() { + + // If you are debugging an E2E test and want to prevent its namespace from being deleted when the test ends (so that you can examine the state of resources in the namespace) you can set E2E_DEBUG_SKIP_CLEANUP env var. + if os.Getenv("E2E_DEBUG_SKIP_CLEANUP") != "" { + GinkgoWriter.Println("Skipping namespace cleanup as E2E_DEBUG_SKIP_CLEANUP is set") + return + } + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + Expect(err).ToNot(HaveOccurred()) + err = k8sClient.Delete(context.Background(), ns, &client.DeleteOptions{PropagationPolicy: ptr.To(metav1.DeletePropagationForeground)}) + + // Error shouldn't occur, UNLESS it's because the NS no longer exists + if err != nil && !apierr.IsNotFound(err) { + Expect(err).ToNot(HaveOccurred()) + } + } + +} + +// EnvNonOLM checks if NON_OLM var is set; this variable is set when testing on GitOps operator that is not installed via OLM +func EnvNonOLM() bool { + _, exists := os.LookupEnv("NON_OLM") + return exists +} + +func EnvLocalRun() bool { + _, exists := os.LookupEnv("LOCAL_RUN") + return exists +} + +// EnvCI checks if CI env var is set; this variable is set when testing on GitOps Operator running via CI pipeline (and using an OLM Subscription) +func EnvCI() bool { + _, exists := os.LookupEnv("CI") + return exists +} + +// GetEnvInOperatorSubscriptionOrDeployment will return the value of an environment variable, in either operator Subscription or operator Deployment, depending on which mode the test is running in. +func GetEnvInOperatorSubscriptionOrDeployment(key string) (*string, error) { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + return nil, nil + } + + if EnvNonOLM() { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator-controller-manager", Namespace: "openshift-gitops-operator"}} + + return deploymentFixture.GetEnv(depl, key) + + } else if EnvCI() { + + sub, err := GetSubscriptionInEnvCIEnvironment(k8sClient) + if err != nil { + return nil, err + } + if sub == nil { + return nil, nil + } + + envVal, err := subscriptionFixture.GetEnv(sub, key) + + return envVal, err + + } else { + + sub := &olmv1alpha1.Subscription{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator", Namespace: "openshift-gitops-operator"}} + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(sub), sub); err != nil { + return nil, err + } + + return subscriptionFixture.GetEnv(sub, key) + + } + +} + +// SetEnvInOperatorSubscriptionOrDeployment will set the value of an environment variable, in either operator Subscription or operator Deployment, depending on which mode the test is running in. +func SetEnvInOperatorSubscriptionOrDeployment(key string, value string) { + + k8sClient, _ := utils.GetE2ETestKubeClient() + + if EnvNonOLM() { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator-controller-manager", Namespace: "openshift-gitops-operator"}} + + deploymentFixture.SetEnv(depl, key, value) + + } else if EnvCI() { + + sub, err := GetSubscriptionInEnvCIEnvironment(k8sClient) + Expect(err).ToNot(HaveOccurred()) + Expect(sub).ToNot(BeNil()) + + subscriptionFixture.SetEnv(sub, key, value) + + } else { + + sub := &olmv1alpha1.Subscription{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator", Namespace: "openshift-gitops-operator"}} + Expect(k8sClient.Get(context.Background(), client.ObjectKeyFromObject(sub), sub)).To(Succeed()) + + subscriptionFixture.SetEnv(sub, key, value) + } +} + +// RemoveEnvFromOperatorSubscriptionOrDeployment will delete an environment variable from either operator Subscription or operator Deployment, depending on which mode the test is running in. +func RemoveEnvFromOperatorSubscriptionOrDeployment(key string) error { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + return err + } + + if EnvNonOLM() { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator-controller-manager", Namespace: "openshift-gitops-operator"}} + + deploymentFixture.RemoveEnv(depl, key) + + } else if EnvCI() { + + sub, err := GetSubscriptionInEnvCIEnvironment(k8sClient) + if err != nil { + return err + } + if sub == nil { + return nil + } + + subscriptionFixture.RemoveEnv(sub, key) + + } else { + + sub := &olmv1alpha1.Subscription{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator", Namespace: "openshift-gitops-operator"}} + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(sub), sub); err != nil { + return err + } + + subscriptionFixture.RemoveEnv(sub, key) + + } + return nil +} + +func GetSubscriptionInEnvCIEnvironment(k8sClient client.Client) (*olmv1alpha1.Subscription, error) { + subscriptionList := olmv1alpha1.SubscriptionList{} + if err := k8sClient.List(context.Background(), &subscriptionList, client.InNamespace("openshift-gitops-operator")); err != nil { + return nil, err + } + + var sub *olmv1alpha1.Subscription + + for idx := range subscriptionList.Items { + currsub := subscriptionList.Items[idx] + + if strings.HasPrefix(currsub.Name, "gitops-operator-") { + sub = &currsub + } + } + + return sub, nil + +} + +// RestoreSubcriptionToDefault ensures that the Subscription (or Deployment env vars) are restored to a default state before each test. +func RestoreSubcriptionToDefault() error { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + return err + } + + // optionalEnvVarsToRemove is a non-exhaustive list of environment variables that are known to be added to Subscription or operator Deployment by tests + optionalEnvVarsToRemove := []string{"DISABLE_DEFAULT_ARGOCD_CONSOLELINK", "CONTROLLER_CLUSTER_ROLE", "SERVER_CLUSTER_ROLE", "ARGOCD_LABEL_SELECTOR"} + + if EnvNonOLM() { + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator-controller-manager", Namespace: "openshift-gitops-operator"}} + + for _, envKey := range optionalEnvVarsToRemove { + deploymentFixture.RemoveEnv(depl, envKey) + } + + if err := waitForAllEnvVarsToBeRemovedFromDeployments(depl.Namespace, optionalEnvVarsToRemove, k8sClient); err != nil { + return err + } + + Eventually(depl, "3m", "1s").Should(deploymentFixture.HaveReadyReplicas(1)) + + } else if EnvCI() { + + sub, err := GetSubscriptionInEnvCIEnvironment(k8sClient) + if err != nil { + return err + } + + if sub != nil { + subscriptionFixture.RemoveSpecConfig(sub) + } + + if err := waitForAllEnvVarsToBeRemovedFromDeployments("openshift-gitops-operator", optionalEnvVarsToRemove, k8sClient); err != nil { + return err + } + + WaitForAllDeploymentsInTheNamespaceToBeReady("openshift-gitops-operator", k8sClient) + + } else if EnvLocalRun() { + // When running locally, there are no cluster resources to clean up + return nil + + } else { + + sub := &olmv1alpha1.Subscription{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator", Namespace: "openshift-gitops-operator"}} + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(sub), sub); err != nil { + return err + } + + subscriptionFixture.RemoveSpecConfig(sub) + + if err := waitForAllEnvVarsToBeRemovedFromDeployments("openshift-gitops-operator", optionalEnvVarsToRemove, k8sClient); err != nil { + return err + } + + WaitForAllDeploymentsInTheNamespaceToBeReady("openshift-gitops-operator", k8sClient) + } + + return nil + +} + +// waitForAllEnvVarsToBeRemovedFromDeployments checks all Deployments in the Namespace, to ensure that none of those Deployments contain environment variables defined within envVarKeys. +// This can be used before a test starts to ensure that Operator or Argo CD containers are back to default state. +func waitForAllEnvVarsToBeRemovedFromDeployments(ns string, envVarKeys []string, k8sClient client.Client) error { + + Eventually(func() bool { + var deplList appsv1.DeploymentList + + if err := k8sClient.List(context.Background(), &deplList, client.InNamespace(ns)); err != nil { + GinkgoWriter.Println(err) + return false + } + + // For each Deployment in the list... + for _, depl := range deplList.Items { + + // If at least one of the Deployments has not been observed, wait and try again + if depl.Generation != depl.Status.ObservedGeneration { + return false + } + + // For each container of the deployment + for _, container := range depl.Spec.Template.Spec.Containers { + + // For each env var we are looking for + for _, envVarKey := range envVarKeys { + + for _, containerEnvKey := range container.Env { + + if containerEnvKey.Name == envVarKey { + GinkgoWriter.Println("Waiting:", containerEnvKey, "is still present in Deployment ", depl.Name) + return false + } + + } + } + } + } + + // All Deployments in NS are reconciled and ready + return true + + }, "3m", "1s").Should(BeTrue()) + + return nil +} + +func WaitForAllDeploymentsInTheNamespaceToBeReady(ns string, k8sClient client.Client) { + + Eventually(func() bool { + var deplList appsv1.DeploymentList + + if err := k8sClient.List(context.Background(), &deplList, client.InNamespace(ns)); err != nil { + GinkgoWriter.Println(err) + return false + } + + for _, depl := range deplList.Items { + + // If at least one of the Deployments has not been observed, wait and try again + if depl.Generation != depl.Status.ObservedGeneration { + return false + } + + if int64(depl.Status.Replicas) != int64(depl.Status.ReadyReplicas) { + return false + } + + } + + // All Deployments in NS are reconciled and ready + return true + + }, "3m", "1s").Should(BeTrue()) + +} + +func WaitForAllStatefulSetsInTheNamespaceToBeReady(ns string, k8sClient client.Client) { + + Eventually(func() bool { + var ssList appsv1.StatefulSetList + + if err := k8sClient.List(context.Background(), &ssList, client.InNamespace(ns)); err != nil { + GinkgoWriter.Println(err) + return false + } + + for _, ss := range ssList.Items { + + // If at least one of the StatefulSets has not been observed, wait and try again + if ss.Generation != ss.Status.ObservedGeneration { + return false + } + + if int64(ss.Status.Replicas) != int64(ss.Status.ReadyReplicas) { + return false + } + + } + + // All StatefulSets in NS are reconciled and ready + return true + + }, "3m", "1s").Should(BeTrue()) + +} + +func WaitForAllPodsInTheNamespaceToBeReady(ns string, k8sClient client.Client) { + + Eventually(func() bool { + var podList corev1.PodList + + if err := k8sClient.List(context.Background(), &podList, client.InNamespace(ns)); err != nil { + GinkgoWriter.Println(err) + return false + } + + for _, pod := range podList.Items { + for _, containerStatus := range pod.Status.ContainerStatuses { + + if !containerStatus.Ready { + GinkgoWriter.Println(pod.Name, "has container", containerStatus.Name, "which is not ready") + return false + } + } + + } + + // All Pod in NS are ready + return true + + }, "3m", "1s").Should(BeTrue()) + +} + +// Delete all namespaces having a specific label used to identify namespaces that are created by e2e tests. +func ensureTestNamespacesDeleted(ctx context.Context, k8sClient client.Client) error { + + // fetch all namespaces having given label + nsList, err := listE2ETestNamespaces(ctx, k8sClient) + if err != nil { + return fmt.Errorf("unable to delete test namespace: %w", err) + } + + // delete selected namespaces + for _, namespace := range nsList.Items { + if err := deleteNamespace(ctx, namespace.Name, k8sClient); err != nil { + return fmt.Errorf("unable to delete namespace '%s': %w", namespace.Name, err) + } + } + return nil +} + +// deleteNamespace deletes a namespace, and waits for it to be reported as deleted. +func deleteNamespace(ctx context.Context, namespaceParam string, k8sClient client.Client) error { + + GinkgoWriter.Println("Deleting Namespace", namespaceParam) + + // Delete the namespace: + // - Issue a request to Delete the namespace + // - Finally, we check if it has been deleted. + if err := wait.PollUntilContextTimeout(ctx, time.Second*5, time.Minute*6, true, func(ctx context.Context) (done bool, err error) { + // Delete the namespace, if it exists + namespace := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: namespaceParam, + }, + } + if err := k8sClient.Delete(ctx, &namespace); err != nil { + if !apierr.IsNotFound(err) { + GinkgoWriter.Printf("Unable to delete namespace '%s': %v\n", namespaceParam, err) + return false, nil + } + } + + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(&namespace), &namespace); err != nil { + if apierr.IsNotFound(err) { + return true, nil + } else { + GinkgoWriter.Printf("Unable to Get namespace '%s': %v\n", namespaceParam, err) + return false, nil + } + } + + return false, nil + }); err != nil { + return fmt.Errorf("namespace was never deleted, after delete was issued. '%s':%v", namespaceParam, err) + } + + return nil +} + +// Retrieve list of namespaces having a specific label used to identify namespaces that are created by e2e tests. +func listE2ETestNamespaces(ctx context.Context, k8sClient client.Client) (corev1.NamespaceList, error) { + nsList := corev1.NamespaceList{} + + // set e2e label + req, err := labels.NewRequirement(LabelsKey, selection.Equals, []string{LabelsValue}) + if err != nil { + return nsList, fmt.Errorf("unable to set labels while fetching list of test namespace: %w", err) + } + + // fetch all namespaces having given label + err = k8sClient.List(ctx, &nsList, &client.ListOptions{LabelSelector: labels.NewSelector().Add(*req)}) + if err != nil { + return nsList, fmt.Errorf("unable to fetch list of test namespace: %w", err) + } + return nsList, nil +} + +// Update will keep trying to update object until it succeeds, or times out. +func updateWithoutConflict(obj client.Object, modify func(client.Object)) error { + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + return err + } + + err = retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + + return err +} diff --git a/test/openshift/e2e/ginkgo/fixture/gitopsservice/fixture.go b/test/openshift/e2e/ginkgo/fixture/gitopsservice/fixture.go new file mode 100644 index 000000000..56b795192 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/gitopsservice/fixture.go @@ -0,0 +1,31 @@ +package gitopsservice + +import ( + "context" + + . "github.com/onsi/gomega" + gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Update will update a GitOpsService CR. Update will keep trying to update object until it succeeds, or times out. +func Update(obj *gitopsoperatorv1alpha1.GitopsService, modify func(*gitopsoperatorv1alpha1.GitopsService)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/k8s/fixture.go b/test/openshift/e2e/ginkgo/fixture/k8s/fixture.go new file mode 100644 index 000000000..d8862b735 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/k8s/fixture.go @@ -0,0 +1,129 @@ +package k8s + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + + "k8s.io/client-go/util/retry" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + apierrors "k8s.io/apimachinery/pkg/api/errors" +) + +func HaveLabelWithValue(key string, value string) matcher.GomegaMatcher { + + return WithTransform(func(k8sObject client.Object) bool { + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(k8sObject), k8sObject) + if err != nil { + GinkgoWriter.Println("HasLabelWithValue:", err) + return false + } + + labels := k8sObject.GetLabels() + if labels == nil { + return false + } + + return labels[key] == value + + }, BeTrue()) +} + +func NotHaveLabelWithValue(key string, value string) matcher.GomegaMatcher { + + return WithTransform(func(k8sObject client.Object) bool { + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(k8sObject), k8sObject) + if err != nil { + GinkgoWriter.Println("DoesNotHaveLabelWithValue:", err) + return false + } + + labels := k8sObject.GetLabels() + if labels == nil { + return true + } + + return labels[key] != value + + }, BeTrue()) +} + +// ExistByName checks if the given k8s resource exists, when retrieving it by name/namespace. +// - It does NOT check if the resource content matches. It only checks that a resource of that type and name exists. +func ExistByName() matcher.GomegaMatcher { + + return WithTransform(func(k8sObject client.Object) bool { + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(k8sObject), k8sObject) + if err != nil { + GinkgoWriter.Println("Object does not exists in ExistByName:", k8sObject.GetName(), err) + } else { + GinkgoWriter.Println("Object exists in ExistByName:", k8sObject.GetName()) + } + return err == nil + }, BeTrue()) +} + +// NotExistByName checks if the given resource does not exist, when retrieving it by name/namespace. +// Does NOT check if the resource content matches. +func NotExistByName() matcher.GomegaMatcher { + + return WithTransform(func(k8sObject client.Object) bool { + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(k8sObject), k8sObject) + if apierrors.IsNotFound(err) { + return true + } else { + if err != nil { + GinkgoWriter.Println(err) + } + return false + } + }, BeTrue()) +} + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj client.Object, modify func(client.Object)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/namespace/fixture.go b/test/openshift/e2e/ginkgo/fixture/namespace/fixture.go new file mode 100644 index 000000000..e85831653 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/namespace/fixture.go @@ -0,0 +1,64 @@ +package namespace + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + matcher "github.com/onsi/gomega/types" + + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func HavePhase(expectedPhase corev1.NamespacePhase) matcher.GomegaMatcher { + return fetchNamespace(func(ns *corev1.Namespace) bool { + GinkgoWriter.Println("Namespace - HavePhase: Expected:", expectedPhase, "Actual:", ns.Status.Phase) + return ns.Status.Phase == expectedPhase + }) +} + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *corev1.Namespace, modify func(*corev1.Namespace)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchNamespace(f func(*corev1.Namespace) bool) matcher.GomegaMatcher { + + return WithTransform(func(depl *corev1.Namespace) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(depl), depl) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(depl) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/node/fixture.go b/test/openshift/e2e/ginkgo/fixture/node/fixture.go new file mode 100644 index 000000000..8605eb1ea --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/node/fixture.go @@ -0,0 +1,41 @@ +package node + +import ( + "context" + "os" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" +) + +// ExpectHasAtLeastXNodes expects the cluster eventually have X nodes. This can be useful for tests that require multiple nodes for HA. +func ExpectHasAtLeastXNodes(expectedNodesOnCluster int) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + // You can set 'SKIP_HA_TESTS=true' env var if you are running on a cluster with < 3 nodes. + skipHATestsVal := os.Getenv("SKIP_HA_TESTS") + if strings.TrimSpace(strings.ToLower(skipHATestsVal)) == "true" { + Skip("Skipping test that requires multiple nodes, because SKIP_HA_TESTS is set") + return + } + + Eventually(func() bool { + var nodeList corev1.NodeList + + err := k8sClient.List(context.Background(), &nodeList) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + GinkgoWriter.Println("ExpectHasAtLeastXNodes, expected:", expectedNodesOnCluster, "actual:", len(nodeList.Items)) + return len(nodeList.Items) >= expectedNodesOnCluster + + }, "3m", "10s").Should(BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/os/fixture.go b/test/openshift/e2e/ginkgo/fixture/os/fixture.go new file mode 100644 index 000000000..4e1983ada --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/os/fixture.go @@ -0,0 +1,25 @@ +package os + +import ( + "os/exec" + + . "github.com/onsi/ginkgo/v2" +) + +func ExecCommand(cmdArgs ...string) (string, error) { + return ExecCommandWithOutputParam(true, cmdArgs...) +} + +// You probably want to use ExecCommand, unless you need to supress the output of sensitive data (for example, openssl CLI output) +func ExecCommandWithOutputParam(printOutput bool, cmdArgs ...string) (string, error) { + GinkgoWriter.Println("executing command:", cmdArgs) + + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + + output, err := cmd.CombinedOutput() + if printOutput { + GinkgoWriter.Println(string(output)) + } + + return string(output), err +} diff --git a/test/openshift/e2e/ginkgo/fixture/pod/fixture.go b/test/openshift/e2e/ginkgo/fixture/pod/fixture.go new file mode 100644 index 000000000..e646f43c2 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/pod/fixture.go @@ -0,0 +1,68 @@ +package pod + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func GetSpecInitContainerByName(name string, pod corev1.Pod) *corev1.Container { + + for idx := range pod.Spec.InitContainers { + + container := pod.Spec.InitContainers[idx] + if container.Name == name { + return &container + } + } + + return nil +} + +func GetSpecContainerByName(name string, pod corev1.Pod) *corev1.Container { + + for idx := range pod.Spec.Containers { + + container := pod.Spec.Containers[idx] + if container.Name == name { + return &container + } + } + + return nil +} + +func HavePhase(phase corev1.PodPhase) matcher.GomegaMatcher { + return fetchPod(func(pod *corev1.Pod) bool { + GinkgoWriter.Println("Pod HavePhase:", "expected: ", phase, "actual: ", pod.Status.Phase) + return pod.Status.Phase == phase + }) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchPod(f func(*corev1.Pod) bool) matcher.GomegaMatcher { + + return WithTransform(func(pod *corev1.Pod) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(pod), pod) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(pod) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go b/test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go new file mode 100644 index 000000000..2e05c48e6 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/rolebinding/fixture.go @@ -0,0 +1,50 @@ +package rolebinding + +import ( + "context" + "reflect" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + rbacv1 "k8s.io/api/rbac/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func HaveSubject(subjectParam rbacv1.Subject) matcher.GomegaMatcher { + return fetchRoleBinding(func(r *rbacv1.RoleBinding) bool { + for _, subject := range r.Subjects { + + GinkgoWriter.Printf("HaveSubject - ", subject, subjectParam) + if reflect.DeepEqual(subjectParam, subject) { + return true + } + + } + return false + }) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchRoleBinding(f func(*rbacv1.RoleBinding) bool) matcher.GomegaMatcher { + + return WithTransform(func(roleBinding *rbacv1.RoleBinding) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(roleBinding), roleBinding) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(roleBinding) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/route/fixture.go b/test/openshift/e2e/ginkgo/fixture/route/fixture.go new file mode 100644 index 000000000..771dae75d --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/route/fixture.go @@ -0,0 +1,105 @@ +package route + +import ( + "context" + "reflect" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + matcher "github.com/onsi/gomega/types" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/client-go/util/retry" + + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func HaveConditionTypeStatus(expectedConditionType routev1.RouteIngressConditionType, expectedConditionStatus corev1.ConditionStatus) matcher.GomegaMatcher { + return fetchRoute(func(r *routev1.Route) bool { + + GinkgoWriter.Println("Conditions:") + for _, ingress := range r.Status.Ingress { + + for _, condition := range ingress.Conditions { + GinkgoWriter.Println("-", condition.Type, condition.Status) + if condition.Type == expectedConditionType && condition.Status == expectedConditionStatus { + return true + } + } + } + + return false + }) +} + +func HavePort(targetPort intstr.IntOrString) matcher.GomegaMatcher { + return fetchRoute(func(r *routev1.Route) bool { + if r.Spec.Port == nil { + return false + } + GinkgoWriter.Println("HavePort - expected: ", targetPort, "actual:", r.Spec.Port.TargetPort) + return reflect.DeepEqual(r.Spec.Port.TargetPort, targetPort) + }) +} + +func HaveTLS(termination routev1.TLSTerminationType, insecureEdgeTerminationPolicy routev1.InsecureEdgeTerminationPolicyType) matcher.GomegaMatcher { + return fetchRoute(func(r *routev1.Route) bool { + if r.Spec.TLS == nil { + return false + } + GinkgoWriter.Println("HaveTLS - expected:", termination, insecureEdgeTerminationPolicy, "actual:", r.Spec.TLS.Termination, r.Spec.TLS.InsecureEdgeTerminationPolicy) + return r.Spec.TLS.Termination == termination && r.Spec.TLS.InsecureEdgeTerminationPolicy == insecureEdgeTerminationPolicy + }) +} + +func HaveTo(routeTR routev1.RouteTargetReference) matcher.GomegaMatcher { + return fetchRoute(func(r *routev1.Route) bool { + GinkgoWriter.Println("HaveTo - expected:", routeTR, "actual:", r.Spec.To) + return reflect.DeepEqual(routeTR, r.Spec.To) + }) +} + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *routev1.Route, modify func(*routev1.Route)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchRoute(f func(*routev1.Route) bool) matcher.GomegaMatcher { + + return WithTransform(func(route *routev1.Route) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(route), route) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(route) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/secret/fixture.go b/test/openshift/e2e/ginkgo/fixture/secret/fixture.go new file mode 100644 index 000000000..0e8c072c1 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/secret/fixture.go @@ -0,0 +1,100 @@ +package secret + +import ( + "bytes" + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *corev1.Secret, modify func(*corev1.Secret)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) +} + +// Update will keep trying to update object until it succeeds, or times out. +func UpdateWithError(obj *corev1.Secret, modify func(*corev1.Secret)) error { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + + return err +} + +// HaveStringDataKeyValue returns true if Secret has 'key' field under .data map, and the value of that field is equal to 'value' +func HaveStringDataKeyValue(key string, value string) matcher.GomegaMatcher { + return fetchSecret(func(sec *corev1.Secret) bool { + a, exists := sec.Data[key] + if !exists { + return false + } + return string(a) == value + }) + +} + +// HaveDataKeyValue returns true if Secret has 'key' field under .data map, and the value of that field is equal to 'value' +func HaveDataKeyValue(key string, value []byte) matcher.GomegaMatcher { + return fetchSecret(func(sec *corev1.Secret) bool { + a, exists := sec.Data[key] + if !exists { + return false + } + return bytes.Equal(a, value) + }) + +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchSecret(f func(*corev1.Secret) bool) matcher.GomegaMatcher { + + return WithTransform(func(secret *corev1.Secret) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(secret), secret) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(secret) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/statefulset/fixture.go b/test/openshift/e2e/ginkgo/fixture/statefulset/fixture.go new file mode 100644 index 000000000..55cb36251 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/statefulset/fixture.go @@ -0,0 +1,224 @@ +package statefulset + +import ( + "context" + "reflect" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + matcher "github.com/onsi/gomega/types" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + "sigs.k8s.io/controller-runtime/pkg/client" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/util/retry" +) + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *appsv1.StatefulSet, modify func(*appsv1.StatefulSet)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) +} + +func HaveReplicas(replicas int) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + GinkgoWriter.Println("StatefulSet HaveReplicas:", "expected: ", replicas, "actual: ", ss.Status.Replicas) + return ss.Status.Replicas == int32(replicas) && ss.Generation == ss.Status.ObservedGeneration + }) +} + +func HaveReadyReplicas(readyReplicas int) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + GinkgoWriter.Println("StatefulSet HaveReadyReplicas:", "expected: ", readyReplicas, "actual: ", ss.Status.ReadyReplicas) + return ss.Status.ReadyReplicas == int32(readyReplicas) && ss.Generation == ss.Status.ObservedGeneration + }) +} + +func GetTemplateSpecInitContainerByName(name string, depl appsv1.StatefulSet) *corev1.Container { + + for idx := range depl.Spec.Template.Spec.InitContainers { + + container := depl.Spec.Template.Spec.InitContainers[idx] + if container.Name == name { + return &container + } + } + + return nil +} + +func GetTemplateSpecContainerByName(name string, depl appsv1.StatefulSet) *corev1.Container { + + for idx := range depl.Spec.Template.Spec.Containers { + + container := depl.Spec.Template.Spec.Containers[idx] + if container.Name == name { + return &container + } + } + + return nil +} + +func HaveTemplateSpecNodeSelector(nodeSelector map[string]string) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + + templateSpec := ss.Spec.Template.Spec + + if templateSpec.NodeSelector == nil { + GinkgoWriter.Println("HaveTemplateSpecNodeSelector - .spec.template.spec is nil") + return false + } + + GinkgoWriter.Println("HaveTemplateSpecNodeSelector - expected:", nodeSelector, "actual:", templateSpec.NodeSelector) + return reflect.DeepEqual(nodeSelector, templateSpec.NodeSelector) + }) + +} + +func HaveTolerations(tolerations []corev1.Toleration) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + + templateSpec := ss.Spec.Template.Spec + GinkgoWriter.Println("HaveTolerations - expected:", tolerations, "actual:", templateSpec.Tolerations) + + return reflect.DeepEqual(templateSpec.Tolerations, tolerations) + }) +} + +func HaveContainerImage(containerImage string, containerIndex int) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + + containers := ss.Spec.Template.Spec.Containers + + if len(containers) <= containerIndex { + GinkgoWriter.Println("current container slide has length", len(containers), "index is", containerIndex) + return false + } + + return containers[containerIndex].Image == containerImage + + }) +} + +func NotHaveContainerImage(containerImage string, containerIndex int) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + + containers := ss.Spec.Template.Spec.Containers + + if len(containers) <= containerIndex { + GinkgoWriter.Println("current container slide has length", len(containers), "index is", containerIndex) + return false + } + + GinkgoWriter.Println("NotHaveContainerImage - expected:", containerImage, "actual:", containers[containerIndex].Image) + + return containers[containerIndex].Image != containerImage + + }) +} + +func HaveContainerCommandSubstring(expectedCommandSubstring string, containerIndex int) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + + containers := ss.Spec.Template.Spec.Containers + + if len(containers) <= containerIndex { + GinkgoWriter.Println("current container slice has length", len(containers), "index is", containerIndex) + return false + } + + // Combine Command and Args, adding spaces (' ') between the args + var cmdLine string + + for _, val := range containers[containerIndex].Command { + if val == "" { + cmdLine += "\"\"" + " " + } else { + cmdLine += val + " " + } + } + cmdLine = strings.TrimSpace(cmdLine) + + for _, val := range containers[containerIndex].Args { + if val == "" { + cmdLine += "\"\"" + " " + } else { + cmdLine += val + " " + } + } + cmdLine = strings.TrimSpace(cmdLine) + + GinkgoWriter.Println("HaveContainerCommandSubstring: Have:") + GinkgoWriter.Println(cmdLine) + GinkgoWriter.Println("HaveContainerCommandSubstring: Expect:") + GinkgoWriter.Println(expectedCommandSubstring) + + return strings.Contains(cmdLine, expectedCommandSubstring) + + }) +} + +func HaveContainerWithEnvVar(envKey string, envValue string, containerIndex int) matcher.GomegaMatcher { + return fetchStatefulSet(func(ss *appsv1.StatefulSet) bool { + + containers := ss.Spec.Template.Spec.Containers + + if len(containers) <= containerIndex { + GinkgoWriter.Println("current container slice has length", len(containers), "index is", containerIndex) + return false + } + + container := containers[containerIndex] + + for _, env := range container.Env { + if env.Name == envKey { + GinkgoWriter.Println("HaveContainerWithEnvVar - Key ", envKey, " Expected:", envValue, "Actual:", env.Value) + if env.Value == envValue { + return true + } + } + } + + return false + }) +} + +// This is intentionally NOT exported, for now. Create another function in this file/package that calls this function, and export that. +func fetchStatefulSet(f func(*appsv1.StatefulSet) bool) matcher.GomegaMatcher { + + return WithTransform(func(ss *appsv1.StatefulSet) bool { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + GinkgoWriter.Println(err) + return false + } + + err = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(ss), ss) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + return f(ss) + + }, BeTrue()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/subscription/fixture.go b/test/openshift/e2e/ginkgo/fixture/subscription/fixture.go new file mode 100644 index 000000000..7a4b2ab8a --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/subscription/fixture.go @@ -0,0 +1,156 @@ +package subscription + +import ( + "context" + + "k8s.io/client-go/util/retry" + "sigs.k8s.io/controller-runtime/pkg/client" + + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + + . "github.com/onsi/gomega" +) + +func GetEnv(s *olmv1alpha1.Subscription, key string) (*string, error) { + + k8sClient, _, err := utils.GetE2ETestKubeClientWithError() + if err != nil { + return nil, err + } + + if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(s), s); err != nil { + return nil, err + } + if s.Spec == nil { + return nil, nil + } + + if s.Spec.Config == nil { + return nil, nil + } + + if s.Spec.Config.Env == nil { + return nil, nil + } + + for idx := range s.Spec.Config.Env { + + idxEnv := s.Spec.Config.Env[idx] + + if idxEnv.Name == key { + return &idxEnv.Value, nil + } + } + return nil, nil + +} + +func SetEnv(subscription *olmv1alpha1.Subscription, key string, value string) { + + Update(subscription, func(s *olmv1alpha1.Subscription) { + + if s.Spec == nil { + s.Spec = &olmv1alpha1.SubscriptionSpec{} + } + + if s.Spec.Config == nil { + s.Spec.Config = &olmv1alpha1.SubscriptionConfig{} + } + + if s.Spec.Config.Env == nil { + s.Spec.Config.Env = []corev1.EnvVar{} + } + + newEnvVars := []corev1.EnvVar{} + + match := false + for idx := range s.Spec.Config.Env { + + currEnv := s.Spec.Config.Env[idx] + + if currEnv.Name == key { + // replace with the value from the param + newEnvVars = append(newEnvVars, corev1.EnvVar{Name: key, Value: value}) + match = true + } else { + newEnvVars = append(newEnvVars, currEnv) + } + } + + if !match { + newEnvVars = append(newEnvVars, corev1.EnvVar{Name: key, Value: value}) + } + + s.Spec.Config.Env = newEnvVars + + }) + +} + +func RemoveEnv(subscription *olmv1alpha1.Subscription, key string) { + + Update(subscription, func(s *olmv1alpha1.Subscription) { + + if s.Spec == nil { + return + } + + if s.Spec.Config == nil { + return + } + + if s.Spec.Config.Env == nil { + return + } + + newEnvVars := []corev1.EnvVar{} + + for idx := range s.Spec.Config.Env { + + currEnv := s.Spec.Config.Env[idx] + + if currEnv.Name == key { + // skip + } else { + newEnvVars = append(newEnvVars, currEnv) + } + } + + s.Spec.Config.Env = newEnvVars + + }) + +} + +// RemoveSpecConfig removes any configuration data (environment variables) specified under .spec.config of Subscription +func RemoveSpecConfig(sub *olmv1alpha1.Subscription) { + + Update(sub, func(s *olmv1alpha1.Subscription) { + if s.Spec != nil { + s.Spec.Config = nil + } + }) + +} + +// Update will keep trying to update object until it succeeds, or times out. +func Update(obj *olmv1alpha1.Subscription, modify func(*olmv1alpha1.Subscription)) { + k8sClient, _ := utils.GetE2ETestKubeClient() + + err := retry.RetryOnConflict(retry.DefaultRetry, func() error { + // Retrieve the latest version of the object + err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj) + if err != nil { + return err + } + + modify(obj) + + // Attempt to update the object + return k8sClient.Update(context.Background(), obj) + }) + Expect(err).ToNot(HaveOccurred()) + +} diff --git a/test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go b/test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go new file mode 100644 index 000000000..1838356d4 --- /dev/null +++ b/test/openshift/e2e/ginkgo/fixture/utils/fixtureUtils.go @@ -0,0 +1,156 @@ +package utils + +import ( + "os" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + + osappsv1 "github.com/openshift/api/apps/v1" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + + rolloutmanagerv1alpha1 "github.com/argoproj-labs/argo-rollouts-manager/api/v1alpha1" + argov1alpha1api "github.com/argoproj-labs/argocd-operator/api/v1alpha1" + monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" + consolev1 "github.com/openshift/api/console/v1" + routev1 "github.com/openshift/api/route/v1" + securityv1 "github.com/openshift/api/security/v1" + gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" + admissionv1 "k8s.io/api/admissionregistration/v1" + apps "k8s.io/api/apps/v1" + autoscalingv2 "k8s.io/api/autoscaling/v2" + corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" + rbacv1 "k8s.io/api/rbac/v1" + crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + + . "github.com/onsi/gomega" +) + +func GetE2ETestKubeClient() (client.Client, *runtime.Scheme) { + config, err := getSystemKubeConfig() + Expect(err).ToNot(HaveOccurred()) + + k8sClient, scheme, err := getKubeClient(config) + Expect(err).ToNot(HaveOccurred()) + + return k8sClient, scheme +} + +func GetE2ETestKubeClientWithError() (client.Client, *runtime.Scheme, error) { + config, err := getSystemKubeConfig() + if err != nil { + return nil, nil, err + } + + k8sClient, scheme, err := getKubeClient(config) + if err != nil { + return nil, nil, err + } + + return k8sClient, scheme, nil +} + +// getKubeClient returns a controller-runtime Client for accessing K8s API resources used by the controller. +func getKubeClient(config *rest.Config) (client.Client, *runtime.Scheme, error) { + + scheme := runtime.NewScheme() + + if err := corev1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := apps.AddToScheme(scheme); err != nil { + return nil, nil, err + } + if err := rbacv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := admissionv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := monitoringv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := crdv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := argov1beta1api.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := argocdv1alpha1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := gitopsoperatorv1alpha1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := olmv1alpha1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := routev1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := osappsv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := consolev1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + if err := rolloutmanagerv1alpha1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := argov1alpha1api.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := securityv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := networkingv1.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + if err := autoscalingv2.AddToScheme(scheme); err != nil { + return nil, nil, err + } + + k8sClient, err := client.New(config, client.Options{Scheme: scheme}) + if err != nil { + return nil, nil, err + } + + return k8sClient, scheme, nil + +} + +// Retrieve the system-level Kubernetes config (e.g. ~/.kube/config or service account config from volume) +func getSystemKubeConfig() (*rest.Config, error) { + + overrides := clientcmd.ConfigOverrides{} + + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin) + + restConfig, err := clientConfig.ClientConfig() + if err != nil { + return nil, err + } + return restConfig, nil +} diff --git a/test/openshift/e2e/ginkgo/parallel/1-003_validate_console_link_test.go b/test/openshift/e2e/ginkgo/parallel/1-003_validate_console_link_test.go new file mode 100644 index 000000000..e9d370742 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-003_validate_console_link_test.go @@ -0,0 +1,32 @@ +package parallel + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + consolev1 "github.com/openshift/api/console/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-003_validate_console_link", func() { + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + }) + + It("verifies ConsoleLink exists and has expected content", func() { + + consoleLink := &consolev1.ConsoleLink{ObjectMeta: metav1.ObjectMeta{ + Name: "argocd", + }} + Eventually(consoleLink).Should(k8sFixture.ExistByName()) + Expect(string(consoleLink.Spec.Location)).To(Equal("ApplicationMenu")) + Expect(consoleLink.Spec.Text).To(Equal("Cluster Argo CD")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go b/test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go new file mode 100644 index 000000000..9ad6c4796 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-005_validate_route_tls_test.go @@ -0,0 +1,508 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + secretFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/secret" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-005_validate_route_tls", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that certificates can be confirmed on server and webhook Routes", func() { + + ns, nsCleanup := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer nsCleanup() + + By("creating Argo CD with server and appset controller webhook routes") + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example", + Namespace: ns.Name, + }, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + ApplicationSet: &argov1beta1api.ArgoCDApplicationSet{ + Enabled: ptr.To(true), + WebhookServer: argov1beta1api.WebhookServerSpec{ + Host: "example.com", + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("verifying expected resources exist") + + Eventually(argoCD, "2m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCD, "2m", "5s").Should( + And(argocdFixture.HaveApplicationSetControllerStatus("Running"), argocdFixture.HaveServerStatus("Running"))) + + serverRoute := &routev1.Route{ObjectMeta: metav1.ObjectMeta{Name: "example-server", Namespace: ns.Name}} + Eventually(serverRoute).Should(k8sFixture.ExistByName()) + Expect(serverRoute.Spec.To.Kind).To(Equal("Service")) + Expect(serverRoute.Spec.To.Name).To(Equal("example-server")) + Expect(*serverRoute.Spec.To.Weight).To(Equal(int32(100))) + Expect(serverRoute.Spec.TLS.InsecureEdgeTerminationPolicy).To(Equal(routev1.InsecureEdgeTerminationPolicyRedirect)) + Expect(serverRoute.Spec.TLS.Termination).To(Equal(routev1.TLSTerminationReencrypt)) + + webhookRoute := &routev1.Route{ObjectMeta: metav1.ObjectMeta{Name: "example-applicationset-controller-webhook", Namespace: ns.Name}} + Eventually(webhookRoute).Should(k8sFixture.ExistByName()) + Expect(webhookRoute.Spec.To.Kind).To(Equal("Service")) + Expect(webhookRoute.Spec.To.Name).To(Equal("example-applicationset-controller")) + Expect(*webhookRoute.Spec.To.Weight).To(Equal(int32(100))) + Expect(webhookRoute.Spec.TLS.InsecureEdgeTerminationPolicy).To(Equal(routev1.InsecureEdgeTerminationPolicyRedirect)) + Expect(webhookRoute.Spec.TLS.Termination).To(Equal(routev1.TLSTerminationEdge)) + + By("setting an embedded certificate and private key in ArgoCD CR") + + cert := `-----BEGIN CERTIFICATE----- +MIIEbTCCAtWgAwIBAgIUA80/UfgNcx8tYz/XXlo6X8DJzXQwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yNDA5MjUwNDM4MjdaGA8yMTIz +MDQyMDA0MzgyN1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAaIwDQYJKoZIhvcN +AQEBBQADggGPADCCAYoCggGBAJUuv+nO7S02+BHo5zkVg/IwUNSqQhsgKe3Djzsm +ISctrzNgrtUPqxYU0XDPXIS/v4wrtXrbXjlEaVgpTToqt/DRITH/I9FZzFQRQWKb +Gx0g3aH/LFJHHix4KCMPzEcykXba3zJqZei4NeJ7ym/Z5g/gJjGOE2SDVJN7YA9p +WKEgf/+TB6uPkEcgNc+8rFKbwQ63IhqOnHZq0mFaT/DWQUWYqLNZOHIiXjIELjGe +RjzmxlTQd9hWrC+FP1fOz9Ahpnw8oJ+wEpMUSpsAd3FFYUDZW/bj3jwWLT3WtmTb +d5ehpeE/zM5twy4rZXzT43+fsO/ns2YDxsSiujrtwm/Ar5k86S2XTkWro6f/t/Ml +dcIGzUZm2lSRacX1brIhNryHU2ZyVsEKJbS4/7N/wHTqhctSZlJRXkfjPiIC2KHV +YngPAtJ+fSmdULd7rIWcaxsrpnyozVpzYm5U8XRGm/pj2FFHVKPdSBoo2GrkVMyh +oU3+YiFno57wNbrm9ROzMIHhhwIDAQABo1MwUTAdBgNVHQ4EFgQUTbU3O3JsKBC6 +jCLjxTX4zWEAgc8wHwYDVR0jBBgwFoAUTbU3O3JsKBC6jCLjxTX4zWEAgc8wDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAYEAMthyYhEUf5GdrKSMBuWR ++QlsBau/6N2nSxRxM2g4oexQOGUny1r76KrW6o/2V/PYyz/3WgOgSB/4sZxNoeu8 +rsjY9sp/bCWJ6jEmhm2kkVeb3Arix0iNt7BviOCjoVchc31R20JLP0a6WK+KtiV2 +C8qbuOQEkVWY/NVy+buHKqJjNZXyj8ADX0It8rAmaEGMEGkEFtYTnjEYHdkPWfYx +6P9C12PrZySu9+L3eGmylKeDU7dWvBAONbHfHL8W/8pxG1CwObfkTEpzVTlR0SfI +W1dZ9YXb7S5F/0j6GLeUSgvnQZxH4rbc699wC9Y/kt5EozT1xvmKgZ6G6vaU2Mhb +jZnrbB4swXCVf98HDAy8PWrn7BWky9G8SbM5kS6Mj9pQwZnnfF6VLg+uWBBjMh7g +0Ntf+Lv/IC5v+jC7TDKRPCAUGYzBRLMbT0WvK0BVXhp6swCi4qtME/BTsqXA6zzk +5PfEh1b+yuqxbF3bU8rII1LIsXxr96lssl+H0HxPpQKv +-----END CERTIFICATE-----` + + key := `-----BEGIN PRIVATE KEY----- +MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCVLr/pzu0tNvgR +6Oc5FYPyMFDUqkIbICntw487JiEnLa8zYK7VD6sWFNFwz1yEv7+MK7V62145RGlY +KU06Krfw0SEx/yPRWcxUEUFimxsdIN2h/yxSRx4seCgjD8xHMpF22t8yamXouDXi +e8pv2eYP4CYxjhNkg1STe2APaVihIH//kwerj5BHIDXPvKxSm8EOtyIajpx2atJh +Wk/w1kFFmKizWThyIl4yBC4xnkY85sZU0HfYVqwvhT9Xzs/QIaZ8PKCfsBKTFEqb +AHdxRWFA2Vv24948Fi091rZk23eXoaXhP8zObcMuK2V80+N/n7Dv57NmA8bEoro6 +7cJvwK+ZPOktl05Fq6On/7fzJXXCBs1GZtpUkWnF9W6yITa8h1NmclbBCiW0uP+z +f8B06oXLUmZSUV5H4z4iAtih1WJ4DwLSfn0pnVC3e6yFnGsbK6Z8qM1ac2JuVPF0 +Rpv6Y9hRR1Sj3UgaKNhq5FTMoaFN/mIhZ6Oe8DW65vUTszCB4YcCAwEAAQKCAYBJ +9tTF6odjTIav8oZ5ofY6ZMQevI9r/YVsUfI4xE3Zq+falEv6bPtJRmcVBGp9ksg4 +ig8/a3YK9KU6Rbf5Z+as6jMII9SxXlFVOPzvE7HcvkfEosxpusL2D1jvEU0Z27ON +dzUEPQZr3LEyqmeTDzjmlB67oRJyWj7bpGbbHUMJGCD+KPq7j8Fb0ld7uLLDfl+4 +mQm6mwxuFcZa6DkMUl4oUGkMCudWhz2mlLYGec+fMFgTAwz4YPib0ve15F7adWPh +EYqE8cqz3p1r2b9O6MNu0GTK16+388AFVSULImag/525pddohZgPHU8BJAKffGL6 +XCCfQrQBbe6geYsNANx8E34M3fbmkeby41oLY8v8PJOMHvoDREqD7tgqlPgozlD0 +BXlDaxTYLAwbyK+jARvQT60a4V744MMhsJ57GMC69R/YDW7Qbd4hiD3P4XEmqHBz +a/dhsNsJylgTMLFOIr4RnH/82yXyG3J0WTtZP+kRxq1aHaTduSif1SQkFqhr+MkC +gcEAxxmX9UAChk+DuOPsYYtx+kl/0aR8B5tvVQRQDxfij0Km9nXEyTsRE34sFlAk +RxgVUb+DjARPn5OuST/v3HHemGUU2x/L5BYYgtn9waI6vpTA3lllPzTYIr6aZfkb +yaX6UbHk5C9af/0F+xq4pNoSpcafdrE5dJ9JyM/20Q3DRxCN+RY2alezO/UCe0Sf +3OH7Qk2RYgbP1lADV/58oqGpU079N1M4yt6ziyltPC8y/laGOAA00ZGFBPzySs2J +3yXbAoHBAL/RI4s2WsX8ERaa/GXo85q0/LK2Wq8LICm/jxrMAZrVK1u9kSEKgps2 +pGV9hE73y7gBgstrfrUKghSsqwtIwQCXVYFKEzu4l2fojukJ13eCR7YSBqGTM3Jn +PhyjvxoAcmBsKjkoaXAt5+6DtuTVlQmElJB1s/A8us6rwy2GaXAWTHhNGJ5xuSAd +h3nW1Bsg84f5J6Vx0mnW85kAipB16LZFKUSqHpWYZ+Qe9yT0+iS0Fexz/dHmX4WA +eBZ0rulAxQKBwAutkKAt9PfzygIaPE8sYq8PiJO/VhcMIueVrSx1djB49FoYZkZ3 +VHUUPXnBkZ8p5nY5CXo49oKhouNhAKypcSj3JNYFc2wZb66dIqks3s025GkmTS37 +54GCNIQurFaTia8pBAfuTxyatrMXyiTBNb7Le6b2liwk+6rvp8ZzTDTq36jwiJiM +NFMb991LFSVbi+VDr3dUdvRXFRsgLidL3Caqx2drVjVwAo/zChkxm4gXgx/dwztX +kbnNLFj+3UtdaQKBwBfHGRzctAvu3z9qHveTFP+Mh/avXDZurqH+OQMdXuWOnz1U +FnV+FAqhj2d1U71mQj6hEVGeFarjjpR5gwp3DlXAbL0GLbQtgbdDwNNqgOczoygS +u/ezg6Ee4zgxpDLY81S4k9NaCxf42NNcSIO9Zigz4ya1MIULQiz0ZdFy5Acc/IW9 +KNwbRNOSVYTo+IoUX5vvata7cVXla3T/+C1IMHzHvgHhBMGOjvJcVE6kf42lNUKG +bmRiplyqPDisZjJL8QKBwQCupVWTNeEy0YZ+7mwyJZ1DLURRlgUOKx7LhkO1MDn4 +YyjJrDm1Ne3XjNXq/wjaQX5KuUdkXoqAp1emo2nKGqqVjwSkWX6ordO6mLYhGDiA +vDydisaLX4I8x6NZFIabzqpZbmf6pWlxXVsEptXdAeALpxNZ/r/P34UOgF/g5jZB +/r8qFYC5HnDCY72bY52UXON3ktVmhC7PK3JNmruJgunEfC/yOk8YB9Eks7+3+9SR +HkXkOt1cAbJWZruf4j13X4s= +-----END PRIVATE KEY-----` + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + argoCD.Spec.Server.Route.TLS = &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + Certificate: cert, + Key: key, + } + argoCD.Spec.ApplicationSet.WebhookServer.Route.TLS = &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + Certificate: cert, + Key: key, + } + }) + + By("verifying Routes pick up certificate and key data") + + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCD, "3m", "5s").Should( + And(argocdFixture.HaveApplicationSetControllerStatus("Running"), argocdFixture.HaveServerStatus("Running"))) + + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(serverRoute), serverRoute); err != nil { + GinkgoWriter.Println(err) + return false + } + + if serverRoute.Spec.TLS.Certificate != cert { + return false + } + + if serverRoute.Spec.TLS.Key != key { + return false + } + + return true + + }).Should(BeTrue()) + + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(webhookRoute), webhookRoute); err != nil { + GinkgoWriter.Println(err) + return false + } + + if webhookRoute.Spec.TLS.Certificate != cert { + return false + } + + if webhookRoute.Spec.TLS.Key != key { + return false + } + + return true + + }).Should(BeTrue()) + + By("updating ArgoCD to use an external Secret containing certificate and key") + + tlsCRTForSecret := `-----BEGIN CERTIFICATE----- +MIIFrjCCA5agAwIBAgIUbM9O0W6IdumLQodDCDqyckYDr2IwDQYJKoZIhvcNAQEL +BQAwTTELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFRlc3QxDTALBgNVBAoMBFRlc3Qx +DTALBgNVBAsMBFRlc3QxETAPBgNVBAMMCHRlc3QuY29tMCAXDTIzMTEyNjIyMTg0 +N1oYDzIxMjMxMTI3MjIxODQ3WjBNMQswCQYDVQQGEwJVUzENMAsGA1UECAwEVGVz +dDENMAsGA1UECgwEVGVzdDENMAsGA1UECwwEVGVzdDERMA8GA1UEAwwIdGVzdC5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDbgAmnUjFux9u2Xzhi +mno5zjA/YsoXr3eFtK9XtByQMLLyT0hbXoa9gpTeafOs3IkCotPdN+omxm2tN9UA +ebAq+EamWyIF28EA3UbCWWULghveezrmAKSMcqQqby3knbcbGng+ZZjRdC3xc0uz +/sd4FqaLt0UHBDMlpxRskj/S3CDetfyIrKYQcZ5NQjx75aRN8At5OPC1NiWTmlsv +ppa4LLV0HR6AJzq+C6RAmJTcHQOFAq33wZEHHIpoQoGWHHPpT0ut54KIiVTRJ2o4 +MEV4KlBBgL3ux4+v7R0RfVmzgaMEDG1fC9tX8pIofv7wP7WX/5XHTjyAiv8gbpUW +nLiU8FoTDZWxZN+MiCkUvZl8KqotbcUPjhnRdnq4anFwywY1lKILnCIayqzI7mPW +12h39fNwprFz9YFYbLLoQHekir2nLw8ZH83nNyD82YQ3EFm7UnOld6zw/8aURRuQ +C0oOEHyAXsvIyaWAb6lWvplDdCUGQWWr7MVp5YPPhWdtAv7B4QLDUNHGQMU/1Qrq +VBH22lcU7XrCh6GXrRVm+gF7kAuJzkuae0txvk9mHc+8Y0C4/i9C3xU2qHjWcElw +etcHbqOZjDtC8+n8mDD4hDYEMGV54VhXCKwoFLneT2no27S3SVPvNbMfyyNuUa2i +5azKnIf439Cmfww7ImxIpOR5nQIDAQABo4GDMIGAMB0GA1UdDgQWBBQfe95iWKlT +K6BGFov9JFXQTQN0ZjAfBgNVHSMEGDAWgBQfe95iWKlTK6BGFov9JFXQTQN0ZjAP +BgNVHRMBAf8EBTADAQH/MC0GA1UdEQQmMCSCB3dlYmhvb2uCDndlYmhvb2stc2Vy +dmVygglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggIBAH7Vv+Iar1UbF41c9I88 +oIu8iWfLVnAfe/64tULy77x4nfEQiukBJDoZ9m19KEVdPqsFzT6lFB7Fu1oc9A28 +5b1+PEynHcopNK41zF4n4FnIy9h8zJfaPYYCPPMT0v9LzuT5zyF5sXCz0o4KwQJ6 +zrggZme8udl9sWyDxZyFoFPLWtnQFY7vJ9LSM2Gt+XUIuYNwDkvGFs6RfBYJGarX +qq7YHYj0H2x/us3KQCXGX5GzSmM9ewHvaScRpFcCdVwszKwWF0vMvdnh+3P72/Yy +dQvZXyfNiwqaIdznJn/AjzR9K4dHfbY7wMm83WHwWyjzV6CybHbtWpoUIlZtW3TT +gz6MP2z+BhOdMiQA33aO38J2TX/CMkEvkagEiZdS9t3xtpF2LOb5bRIdlENtZU0i +LnhgWEpJmswxBtuJ0d/zcyUlvK7FYoJZB7pT3YX/321HXZVCKyw+xrinwQoI3RnX +7u0TZ3MqtSKEwCyDWYRJDbs6XUX1G0q7jXBf1+3cd+lBdOZ4Kl5B4YSU9hcFxAuO +4a1eFXBdmT8PnwoTizFvag3IgBXkf8PqcKNvSMU6UKcD5LYTwRGK3JVl1L79gkrb +LmWEfOXFHgSlMIZkEs41TiopXy8p/LSera8NR86Q3mTZ7rRdEveOb6ZLJksRqaqr +UVwpFuaKz5vTCD36Gmmy/u8y +-----END CERTIFICATE-----` + + tlsKeyForSecret := `-----BEGIN PRIVATE KEY----- +MIIJQAIBADANBgkqhkiG9w0BAQEFAASCCSowggkmAgEAAoICAQDbgAmnUjFux9u2 +Xzhimno5zjA/YsoXr3eFtK9XtByQMLLyT0hbXoa9gpTeafOs3IkCotPdN+omxm2t +N9UAebAq+EamWyIF28EA3UbCWWULghveezrmAKSMcqQqby3knbcbGng+ZZjRdC3x +c0uz/sd4FqaLt0UHBDMlpxRskj/S3CDetfyIrKYQcZ5NQjx75aRN8At5OPC1NiWT +mlsvppa4LLV0HR6AJzq+C6RAmJTcHQOFAq33wZEHHIpoQoGWHHPpT0ut54KIiVTR +J2o4MEV4KlBBgL3ux4+v7R0RfVmzgaMEDG1fC9tX8pIofv7wP7WX/5XHTjyAiv8g +bpUWnLiU8FoTDZWxZN+MiCkUvZl8KqotbcUPjhnRdnq4anFwywY1lKILnCIayqzI +7mPW12h39fNwprFz9YFYbLLoQHekir2nLw8ZH83nNyD82YQ3EFm7UnOld6zw/8aU +RRuQC0oOEHyAXsvIyaWAb6lWvplDdCUGQWWr7MVp5YPPhWdtAv7B4QLDUNHGQMU/ +1QrqVBH22lcU7XrCh6GXrRVm+gF7kAuJzkuae0txvk9mHc+8Y0C4/i9C3xU2qHjW +cElwetcHbqOZjDtC8+n8mDD4hDYEMGV54VhXCKwoFLneT2no27S3SVPvNbMfyyNu +Ua2i5azKnIf439Cmfww7ImxIpOR5nQIDAQABAoIB/2wImLfBvJLJy1n3g8kEPyQ0 +V4rbFJyTwEAOrj58Z5KQZYLdgr91xtt/acYOX+C0qrqhaaV338c14sVetXeGbS65 +BAzczeIURuol/q2pUhJX91+JR3Ps3RBDXImGLxBWj8jHPmd3mb99bx9nn9r3izWP +8GjTyyWo64OcuHC3irI9pe/3olOiphlx0ng0IZDZdgTmIL+JRu/ptpTvY/IQDB6Z +4rVDn79zj3X6RN2GO74aiaDtsLJAkyDs6zJliWJYnrQ2UwlE6PpKnXRT8fO1zntW +WCnlM5ZSomX0TlpNV9kB9ToI48vkChE/UrCb0N5ufPJS2WU/HIgn4WoVA0wd1rqO +OYfJB1IMY2RoWR9CXO0U51tCji+M83ATq+Fl0Xbxl8grn/q0PWlhmUvS9/Fe8aPA +yVTkEjT2j7MQGtqAO7L+xTUfVfGpFkDUn+QkM8BgNcygagN5ViOfWDFgMgjaFLrd +RZMh9kBi3Qjigj0NP4RaK4/ixURMT/FfwiRwEaH/1O1KXB3a0vanVuiXj5+oCrSE +gRBXdRt2+5FOtli8asre7NLk9unTDY1iEiIsVY8nIV+zmWhf2mR5MB34EoTEIunb +OaP9kbiJI6MctKoCsfsWNHfUDPsvriQevG65WETZ1/JKxxjxYlv/Xg702Cnk91Qv +DPrdZCbunMTP3pk5KMECggEBAO0W6hWye+r6e8aBX431Vhv78FDE/suE4iWeCCbA +to7gTnwWZfAB9ynp61bJDS7jXon7Vk0ExkB6nxNTIEj+Yn86M3+UjjuoadCL6hhL +h6xpkc1h1mj5A4IR/yi7RQgHmjKGHURgKyFIwAMYPXNVYD1Ozn9DyGmhG4LcGVQS +zfqclJu5oBCegAkf8EjIaDqMZGJZefxp8UYQy9FjAH1zzG/DXiEWgSPuwoeAu8Ep +SCKsc8EbmxLl9HvJCwvrVaqfuUygLESc/hZZoUFN6fAOQst2B5FS/ZklUECCGiiW +7/8nnL7wbILV+AcGYVQrUBij9CtUzBZpcMMkHREkmZeN6wkCggEBAO0B+C+kAoat +UCfFG5I2Ds4Cro71AEpuWvEl6wtp5WKiZYuHR4ssGDUOshD4uLb44y4mqTphTiU+ +REV0RLQ/9mgFEmErK2glqkRKdskophbPTGQgwxgmfdQWe0Q42yuo47ljNZVEO201 +SxgpOrHlRYzOQ9XGJmuduKxnrarOYfEXJu1WiGbsiEtY/mrMOov6rcbNsZqsWYqG +kmE5Msg1PsuFvlQ9ndVmE+pd3rEIhYxicD8pyFvonvi2uMmR8HmNShWKi1FZxq8e +OlIgdsY4BuqnNUrnQprhm0hG5cGwcl5auL2+Jc5Uagm/egvtwxPhx+pVYcimKOL9 +CutpY7BeuvUCggEAC6UrfENXCNSizb4/Bkb9osQ+KolyhmaRgQ2BEv42OVBVKo0j +FqXSERH3SDz508rBMv/QXloUrsgXFijoFg3AosUmEGcokU+VWvP0XJshH9vTmIXs +tR0+Cd5+bO691kYhUcf6mggrNihPnhdLtWWFI53CUMfwiRertULAT7vYuC2Gsxtr +/ET8vvX9pGWLkQyiRZ5lenttqWZbzH4TYRYV/YtYDUIAt9YbYfJ1xmgTrfhQezSy +6ju3RXk7fKtjesz7mgLoCbq4VDq0y/NawTrCFyJF/uJXqHUHuxNo24OGaD722P4Q +JmECHL44e5zhA0TSUmqI17T4H+2fK99jV+lVmQKCAQB2nTi3pw54ln56GOSOjS1l +nuP7udQWbBppe7+ha7MYZQwLA34jwcKvsxYc9k2DjRYtf73L8OzqKLqERAcqaqSI +NJmZNcC4k7keCmJelFBjNAYYSmk5SfJJVaMFZqsRs6mcm3Eyrf5LzpMxmVi9tW/U +Y1qBv3R1AW9uIUlCJZ3QyfR6bYdAc3pWs0hI7MMUUTXtO/552W3KrUTPEZA/sJ4n +v1yczmWSak7nSWltEkW8F3vzsJaMoOQGt3PNtZMzUinUlAzbfuG3vJoVhhfLZjjX +8Szzur+Twfsz9f+Aqyzh2eeBVouXMpoLHOAY3jp2VdX2ihqxD6+AwoFXhdwVZaON +AoIBAF0/qvwsFThhB9a1wnXuGx1OBY+9owIoinIF2qNcHuqeontxfLWBg1izelJg +gxaATIMvpXgt7y5cBx6fLnylpLgl+TNXCrsrcLnXwJz0Neg/gcSZfcnqwhAhTio9 +iYLVJiK8wnh0pXONutGSasgq3tJLyrzT2+1L5jYKUaFkojIR16sHjo3/MJMPTHvL +fF1DX7y6acz3JXrGJYQsqcrVodSfcGZK/RJQkdvrSdBRZYgWq+CBYViOxkN7cscr +ruQ/DZH/ZCIxVckbuVsAMqdCqAO0gX83eEp7elfAVlnLhvxPluxISuXaJmhJNafr +Xq+NinfrqOLJkIZ/u/PJu4KqN3M= +-----END PRIVATE KEY-----` + + tlsDataSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "tls-data-secret", + Namespace: ns.Name, + }, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + "tls.crt": ([]byte)(tlsCRTForSecret), + "tls.key": ([]byte)(tlsKeyForSecret), + }, + } + Expect(k8sClient.Create(ctx, tlsDataSecret)).To(Succeed()) + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + argoCD.Spec.Server.Route.TLS = &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-data-secret", + }, + Certificate: "", + Key: "", + } + argoCD.Spec.ApplicationSet.WebhookServer.Route.TLS = &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + ExternalCertificate: &routev1.LocalObjectReference{ + Name: "tls-data-secret", + }, + Certificate: "", + Key: "", + } + }) + + By("validating that Routes pickup certificate and key from external Secret") + + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(serverRoute), serverRoute); err != nil { + GinkgoWriter.Println(err) + return false + } + + if serverRoute.Spec.TLS.Certificate != tlsCRTForSecret { + return false + } + + if serverRoute.Spec.TLS.Key != tlsKeyForSecret { + return false + } + + return true + + }).Should(BeTrue()) + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(webhookRoute), webhookRoute); err != nil { + GinkgoWriter.Println(err) + return false + } + + if webhookRoute.Spec.TLS.Certificate != tlsCRTForSecret { + return false + } + + if webhookRoute.Spec.TLS.Key != tlsKeyForSecret { + return false + } + + return true + + }).Should(BeTrue()) + + By("updating the cert/key data of the external secret") + + newTLSCRTForSecret := `-----BEGIN CERTIFICATE----- +MIIEbTCCAtWgAwIBAgIUA80/UfgNcx8tYz/XXlo6X8DJzXQwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAgFw0yNDA5MjUwNDM4MjdaGA8yMTIz +MDQyMDA0MzgyN1owRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCAaIwDQYJKoZIhvcN +AQEBBQADggGPADCCAYoCggGBAJUuv+nO7S02+BHo5zkVg/IwUNSqQhsgKe3Djzsm +ISctrzNgrtUPqxYU0XDPXIS/v4wrtXrbXjlEaVgpTToqt/DRITH/I9FZzFQRQWKb +Gx0g3aH/LFJHHix4KCMPzEcykXba3zJqZei4NeJ7ym/Z5g/gJjGOE2SDVJN7YA9p +WKEgf/+TB6uPkEcgNc+8rFKbwQ63IhqOnHZq0mFaT/DWQUWYqLNZOHIiXjIELjGe +RjzmxlTQd9hWrC+FP1fOz9Ahpnw8oJ+wEpMUSpsAd3FFYUDZW/bj3jwWLT3WtmTb +d5ehpeE/zM5twy4rZXzT43+fsO/ns2YDxsSiujrtwm/Ar5k86S2XTkWro6f/t/Ml +dcIGzUZm2lSRacX1brIhNryHU2ZyVsEKJbS4/7N/wHTqhctSZlJRXkfjPiIC2KHV +YngPAtJ+fSmdULd7rIWcaxsrpnyozVpzYm5U8XRGm/pj2FFHVKPdSBoo2GrkVMyh +oU3+YiFno57wNbrm9ROzMIHhhwIDAQABo1MwUTAdBgNVHQ4EFgQUTbU3O3JsKBC6 +jCLjxTX4zWEAgc8wHwYDVR0jBBgwFoAUTbU3O3JsKBC6jCLjxTX4zWEAgc8wDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAYEAMthyYhEUf5GdrKSMBuWR ++QlsBau/6N2nSxRxM2g4oexQOGUny1r76KrW6o/2V/PYyz/3WgOgSB/4sZxNoeu8 +rsjY9sp/bCWJ6jEmhm2kkVeb3Arix0iNt7BviOCjoVchc31R20JLP0a6WK+KtiV2 +C8qbuOQEkVWY/NVy+buHKqJjNZXyj8ADX0It8rAmaEGMEGkEFtYTnjEYHdkPWfYx +6P9C12PrZySu9+L3eGmylKeDU7dWvBAONbHfHL8W/8pxG1CwObfkTEpzVTlR0SfI +W1dZ9YXb7S5F/0j6GLeUSgvnQZxH4rbc699wC9Y/kt5EozT1xvmKgZ6G6vaU2Mhb +jZnrbB4swXCVf98HDAy8PWrn7BWky9G8SbM5kS6Mj9pQwZnnfF6VLg+uWBBjMh7g +0Ntf+Lv/IC5v+jC7TDKRPCAUGYzBRLMbT0WvK0BVXhp6swCi4qtME/BTsqXA6zzk +5PfEh1b+yuqxbF3bU8rII1LIsXxr96lssl+H0HxPpQKv +-----END CERTIFICATE-----` + + newTLSKeyForSecret := `-----BEGIN PRIVATE KEY----- +MIIG/QIBADANBgkqhkiG9w0BAQEFAASCBucwggbjAgEAAoIBgQCVLr/pzu0tNvgR +6Oc5FYPyMFDUqkIbICntw487JiEnLa8zYK7VD6sWFNFwz1yEv7+MK7V62145RGlY +KU06Krfw0SEx/yPRWcxUEUFimxsdIN2h/yxSRx4seCgjD8xHMpF22t8yamXouDXi +e8pv2eYP4CYxjhNkg1STe2APaVihIH//kwerj5BHIDXPvKxSm8EOtyIajpx2atJh +Wk/w1kFFmKizWThyIl4yBC4xnkY85sZU0HfYVqwvhT9Xzs/QIaZ8PKCfsBKTFEqb +AHdxRWFA2Vv24948Fi091rZk23eXoaXhP8zObcMuK2V80+N/n7Dv57NmA8bEoro6 +7cJvwK+ZPOktl05Fq6On/7fzJXXCBs1GZtpUkWnF9W6yITa8h1NmclbBCiW0uP+z +f8B06oXLUmZSUV5H4z4iAtih1WJ4DwLSfn0pnVC3e6yFnGsbK6Z8qM1ac2JuVPF0 +Rpv6Y9hRR1Sj3UgaKNhq5FTMoaFN/mIhZ6Oe8DW65vUTszCB4YcCAwEAAQKCAYBJ +9tTF6odjTIav8oZ5ofY6ZMQevI9r/YVsUfI4xE3Zq+falEv6bPtJRmcVBGp9ksg4 +ig8/a3YK9KU6Rbf5Z+as6jMII9SxXlFVOPzvE7HcvkfEosxpusL2D1jvEU0Z27ON +dzUEPQZr3LEyqmeTDzjmlB67oRJyWj7bpGbbHUMJGCD+KPq7j8Fb0ld7uLLDfl+4 +mQm6mwxuFcZa6DkMUl4oUGkMCudWhz2mlLYGec+fMFgTAwz4YPib0ve15F7adWPh +EYqE8cqz3p1r2b9O6MNu0GTK16+388AFVSULImag/525pddohZgPHU8BJAKffGL6 +XCCfQrQBbe6geYsNANx8E34M3fbmkeby41oLY8v8PJOMHvoDREqD7tgqlPgozlD0 +BXlDaxTYLAwbyK+jARvQT60a4V744MMhsJ57GMC69R/YDW7Qbd4hiD3P4XEmqHBz +a/dhsNsJylgTMLFOIr4RnH/82yXyG3J0WTtZP+kRxq1aHaTduSif1SQkFqhr+MkC +gcEAxxmX9UAChk+DuOPsYYtx+kl/0aR8B5tvVQRQDxfij0Km9nXEyTsRE34sFlAk +RxgVUb+DjARPn5OuST/v3HHemGUU2x/L5BYYgtn9waI6vpTA3lllPzTYIr6aZfkb +yaX6UbHk5C9af/0F+xq4pNoSpcafdrE5dJ9JyM/20Q3DRxCN+RY2alezO/UCe0Sf +3OH7Qk2RYgbP1lADV/58oqGpU079N1M4yt6ziyltPC8y/laGOAA00ZGFBPzySs2J +3yXbAoHBAL/RI4s2WsX8ERaa/GXo85q0/LK2Wq8LICm/jxrMAZrVK1u9kSEKgps2 +pGV9hE73y7gBgstrfrUKghSsqwtIwQCXVYFKEzu4l2fojukJ13eCR7YSBqGTM3Jn +PhyjvxoAcmBsKjkoaXAt5+6DtuTVlQmElJB1s/A8us6rwy2GaXAWTHhNGJ5xuSAd +h3nW1Bsg84f5J6Vx0mnW85kAipB16LZFKUSqHpWYZ+Qe9yT0+iS0Fexz/dHmX4WA +eBZ0rulAxQKBwAutkKAt9PfzygIaPE8sYq8PiJO/VhcMIueVrSx1djB49FoYZkZ3 +VHUUPXnBkZ8p5nY5CXo49oKhouNhAKypcSj3JNYFc2wZb66dIqks3s025GkmTS37 +54GCNIQurFaTia8pBAfuTxyatrMXyiTBNb7Le6b2liwk+6rvp8ZzTDTq36jwiJiM +NFMb991LFSVbi+VDr3dUdvRXFRsgLidL3Caqx2drVjVwAo/zChkxm4gXgx/dwztX +kbnNLFj+3UtdaQKBwBfHGRzctAvu3z9qHveTFP+Mh/avXDZurqH+OQMdXuWOnz1U +FnV+FAqhj2d1U71mQj6hEVGeFarjjpR5gwp3DlXAbL0GLbQtgbdDwNNqgOczoygS +u/ezg6Ee4zgxpDLY81S4k9NaCxf42NNcSIO9Zigz4ya1MIULQiz0ZdFy5Acc/IW9 +KNwbRNOSVYTo+IoUX5vvata7cVXla3T/+C1IMHzHvgHhBMGOjvJcVE6kf42lNUKG +bmRiplyqPDisZjJL8QKBwQCupVWTNeEy0YZ+7mwyJZ1DLURRlgUOKx7LhkO1MDn4 +YyjJrDm1Ne3XjNXq/wjaQX5KuUdkXoqAp1emo2nKGqqVjwSkWX6ordO6mLYhGDiA +vDydisaLX4I8x6NZFIabzqpZbmf6pWlxXVsEptXdAeALpxNZ/r/P34UOgF/g5jZB +/r8qFYC5HnDCY72bY52UXON3ktVmhC7PK3JNmruJgunEfC/yOk8YB9Eks7+3+9SR +HkXkOt1cAbJWZruf4j13X4s= +-----END PRIVATE KEY-----` + + secretFixture.Update(tlsDataSecret, func(s *corev1.Secret) { + s.Data = map[string][]byte{ + "tls.crt": ([]byte)(newTLSCRTForSecret), + "tls.key": ([]byte)(newTLSKeyForSecret), + } + }) + + By("verifying the Routes pick up the updated certificate/key data from the Secret") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(serverRoute), serverRoute); err != nil { + GinkgoWriter.Println(err) + return false + } + + if serverRoute.Spec.TLS.Certificate != newTLSCRTForSecret { + return false + } + + if serverRoute.Spec.TLS.Key != newTLSKeyForSecret { + return false + } + + return true + + }).Should(BeTrue()) + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(webhookRoute), webhookRoute); err != nil { + GinkgoWriter.Println(err) + return false + } + + if webhookRoute.Spec.TLS.Certificate != newTLSCRTForSecret { + return false + } + + if webhookRoute.Spec.TLS.Key != newTLSKeyForSecret { + return false + } + + return true + + }).Should(BeTrue()) + + Eventually(argoCD, "2m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCD).Should( + And(argocdFixture.HaveApplicationSetControllerStatus("Running"), argocdFixture.HaveServerStatus("Running"))) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-007_validate_namespace_scoped_install_test.go b/test/openshift/e2e/ginkgo/parallel/1-007_validate_namespace_scoped_install_test.go new file mode 100644 index 000000000..72e3ef417 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-007_validate_namespace_scoped_install_test.go @@ -0,0 +1,104 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deplFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + secretFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/secret" + ssFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-007_validate_namespace_scoped_install", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures namespace-scoped ArgoCD install has all the expected K8s resources", func() { + + By("creating namespace-scoped ArgoCD") + ns, nsCleanup := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer nsCleanup() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd", + Namespace: ns.Name, + }, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying expected secrets, deployments, and statefulset") + secretsShouldExist := []string{"argocd-ca", "argocd-cluster", "argocd-default-cluster-config", "argocd-secret", "argocd-tls"} + for _, secret := range secretsShouldExist { + Eventually(&corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: secret, Namespace: ns.Name}}).Should(k8sFixture.ExistByName()) + } + + deploymentsShouldExist := []string{"argocd-redis", "argocd-server", "argocd-repo-server"} + for _, depl := range deploymentsShouldExist { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: depl, Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deplFixture.HaveReplicas(1)) + Eventually(depl).Should(deplFixture.HaveReadyReplicas(1)) + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(statefulSet).Should(ssFixture.HaveReplicas(1)) + Eventually(statefulSet).Should(ssFixture.HaveReadyReplicas(1)) + + By("verifying 'argocd-default-cluster-config' cluster secret") + clusterSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-default-cluster-config", Namespace: ns.Name}, + } + Eventually(clusterSecret).Should(secretFixture.HaveStringDataKeyValue("namespaces", ns.Name)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-008_validate-custom-argocd-namespace_test.go b/test/openshift/e2e/ginkgo/parallel/1-008_validate-custom-argocd-namespace_test.go new file mode 100644 index 000000000..3e41459bf --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-008_validate-custom-argocd-namespace_test.go @@ -0,0 +1,105 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + appFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-008_validate-custom-argocd-namespace", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("creates a custom namespace-scoped Argo CD namespace and verifies the Argo CD instance is able to deploy to that NS", func() { + + By("creating ArgoCD in a custom namespace") + test1_8_customNS, cleanupFn := fixture.CreateNamespaceWithCleanupFunc("test-1-8-custom") + defer cleanupFn() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: test1_8_customNS.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + Eventually(argoCD, "2m", "5s").Should(argocdFixture.BeAvailable()) + + By("waiting for all containers to be ready in the Namespace") + fixture.WaitForAllDeploymentsInTheNamespaceToBeReady(test1_8_customNS.Name, k8sClient) + fixture.WaitForAllStatefulSetsInTheNamespaceToBeReady(test1_8_customNS.Name, k8sClient) + fixture.WaitForAllPodsInTheNamespaceToBeReady(test1_8_customNS.Name, k8sClient) + + By("creating a test Argo CD Application") + + app := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "validate-custom-argocd", Namespace: test1_8_customNS.Name}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: test1_8_customNS.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("verifying Argo CD is successfully able to reconcile and deploy the resources of the test Argo CD Application") + + Eventually(app, "60s", "1s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app, "60s", "1s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-012_validate-managed-by-chain_test.go b/test/openshift/e2e/ginkgo/parallel/1-012_validate-managed-by-chain_test.go new file mode 100644 index 000000000..9cc8c8e0d --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-012_validate-managed-by-chain_test.go @@ -0,0 +1,249 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + appFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + secretFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/secret" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-012_validate-managed-by-chain", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that namespace-scoped Argo CD instance is able to managed other namespaces, including when those namespaces are deleted", func() { + + By("creating ArgoCD instance and 2 custom namespaces ") + + nsTest_1_12_custom, cleanupFunc1 := fixture.CreateNamespaceWithCleanupFunc("test-1-12-custom") + defer cleanupFunc1() + + nsTest_1_12_custom2, cleanupFunc2 := fixture.CreateNamespaceWithCleanupFunc("test-1-12-custom2") + defer cleanupFunc2() + + randomNS, cleanupFunc3 := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc3() + + argoCDRandomNS := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: randomNS.Name}, + } + Expect(k8sClient.Create(ctx, argoCDRandomNS)).To(Succeed()) + + Eventually(argoCDRandomNS, "4m", "5s").Should(argocdFixture.BeAvailable()) + + By("configuring test-1-12-custom to be managed by Argo CD instance") + + k8sFixture.Update(&nsTest_1_12_custom, func(obj client.Object) { + nsObj, ok := obj.(*corev1.Namespace) + Expect(ok).To(BeTrue()) + if nsObj.Labels == nil { + nsObj.Labels = map[string]string{} + } + nsObj.Labels["argocd.argoproj.io/managed-by"] = argoCDRandomNS.Namespace + }) + + // Verify Role/RoleBinding for the managed namespace is validate + expectRoleAndRoleBindingAreValidForManagedNamespace := func(managedNS string) { + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: managedNS}}).Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: managedNS}}).Should(k8sFixture.ExistByName()) + + rb := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: managedNS}} + Eventually(rb).Should(k8sFixture.ExistByName()) + + Expect(rb.RoleRef.APIGroup).To(Equal("rbac.authorization.k8s.io")) + Expect(rb.RoleRef.Kind).To(Equal("Role")) + Expect(rb.RoleRef.Name).To(Equal("argocd-argocd-server")) + Expect(len(rb.Subjects)).To(Equal(1)) + Expect(rb.Subjects[0]).To(Equal(rbacv1.Subject{Kind: "ServiceAccount", Name: "argocd-argocd-server", Namespace: argoCDRandomNS.Namespace})) + } + expectRoleAndRoleBindingAreValidForManagedNamespace(nsTest_1_12_custom.Name) + + By("verifying 'argocd-default-cluster-config' cluster secret references both argo cd ns and custom ns 1") + clusterSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-default-cluster-config", Namespace: argoCDRandomNS.Namespace}, + } + Eventually(clusterSecret).Should(secretFixture.HaveStringDataKeyValue("namespaces", + argoCDRandomNS.Namespace+","+nsTest_1_12_custom.Name)) + + By("creating Argo CD Application targeting test-1-12-custom") + app := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "test-1-12-custom", Namespace: argoCDRandomNS.Namespace}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: nsTest_1_12_custom.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("verifying Argo CD is successfully able to reconcile and deploy the resources of the test Argo CD Application, into test-1-12-custom") + + Eventually(app, "4m", "5s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app, "4m", "5s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + By("setting test-1-12-custom2 to be managed by Argo CD instance") + k8sFixture.Update(&nsTest_1_12_custom2, func(obj client.Object) { + nsObj, ok := obj.(*corev1.Namespace) + Expect(ok).To(BeTrue()) + if nsObj.Labels == nil { + nsObj.Labels = map[string]string{} + } + nsObj.Labels["argocd.argoproj.io/managed-by"] = argoCDRandomNS.Namespace + + }) + + By("validating role/rolebindings are valid for second managed namespace") + expectRoleAndRoleBindingAreValidForManagedNamespace(nsTest_1_12_custom2.Name) + + By("validating Argo CD is able to deploy to second managed namespace") + app2 := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "test-1-12-custom2", Namespace: argoCDRandomNS.Namespace}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: nsTest_1_12_custom2.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + }, + }, + } + Expect(k8sClient.Create(ctx, app2)).To(Succeed()) + + Eventually(app2, "60s", "1s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app2, "60s", "1s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + By("deleting all Argo CD applications and first managed namespace") + + Expect(k8sClient.Delete(ctx, app)).To(Succeed()) + Expect(k8sClient.Delete(ctx, app2)).To(Succeed()) + + Expect(k8sClient.Delete(ctx, &nsTest_1_12_custom)).To(Succeed()) + + By("verifying 'argocd-default-cluster-config' cluster secret references both argo cd ns and custom ns 2 (but not custom ns 1, since it was deleted)") + clusterSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-default-cluster-config", Namespace: argoCDRandomNS.Namespace}, + } + Eventually(clusterSecret).Should(secretFixture.HaveStringDataKeyValue("namespaces", + argoCDRandomNS.Namespace+","+nsTest_1_12_custom2.Name)) + + By("recreating Argo CD applications") + + nsTest_1_12_custom, cleanupFunc4 := fixture.CreateNamespaceWithCleanupFunc("test-1-12-custom") + defer cleanupFunc4() + + app = &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "test-1-12-custom", Namespace: argoCDRandomNS.Namespace}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: nsTest_1_12_custom.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + Retry: &argocdv1alpha1.RetryStrategy{ + Limit: 5, + }, + }, + }, + } + app2 = &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "test-1-12-custom2", Namespace: argoCDRandomNS.Namespace}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: nsTest_1_12_custom2.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + Retry: &argocdv1alpha1.RetryStrategy{ + Limit: 5, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + Expect(k8sClient.Create(ctx, app2)).To(Succeed()) + + By("verifying Argo CD can deploy to managed NS 2, but can no longer deploy to managed NS 1") + + Eventually(app, "1m", "1s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusMissing)) + Eventually(app, "1m", "1s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeUnknown)) + + Eventually(app2, "1m", "1s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app2, "1m", "1s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-019_validate_volume_mounts_test.go b/test/openshift/e2e/ginkgo/parallel/1-019_validate_volume_mounts_test.go new file mode 100644 index 000000000..7f6baed68 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-019_validate_volume_mounts_test.go @@ -0,0 +1,267 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-019_validate_volume_mounts", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that Argo CD components have expected volumes and volume mounts", func() { + + By("creating new namespace-scoped Argo CD instance") + randomNS, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCDRandomNS := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: randomNS.Name}, + } + Expect(k8sClient.Create(ctx, argoCDRandomNS)).To(Succeed()) + + Eventually(argoCDRandomNS, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying volumemounts and volumes of Argo CD Server") + argocdServerDepl := appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: randomNS.Name}} + + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(&argocdServerDepl), &argocdServerDepl)).To(Succeed()) + + Expect(argocdServerDepl.Spec.Template.Spec.Containers[0].VolumeMounts).To(Equal([]corev1.VolumeMount{ + {Name: "ssh-known-hosts", MountPath: "/app/config/ssh"}, + {Name: "tls-certs", MountPath: "/app/config/tls"}, + {Name: "argocd-repo-server-tls", MountPath: "/app/config/server/tls"}, + {Name: "argocd-operator-redis-tls", MountPath: "/app/config/server/tls/redis"}, + {Name: "plugins-home", MountPath: "/home/argocd"}, + {Name: "argocd-cmd-params-cm", MountPath: "/home/argocd/params"}, + {Name: "tmp", MountPath: "/tmp"}, + })) + + Expect(argocdServerDepl.Spec.Template.Spec.Volumes).To(Equal([]corev1.Volume{ + { + Name: "ssh-known-hosts", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-ssh-known-hosts-cm"}}, + }, + }, + { + Name: "tls-certs", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-tls-certs-cm"}}, + }, + }, + { + Name: "argocd-repo-server-tls", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: ptr.To(int32(420)), + SecretName: "argocd-repo-server-tls", + Optional: ptr.To(true), + }, + }, + }, + { + Name: "argocd-operator-redis-tls", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: ptr.To(int32(420)), + SecretName: "argocd-operator-redis-tls", + Optional: ptr.To(true), + }, + }, + }, + { + Name: "plugins-home", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "argocd-cmd-params-cm", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + Items: []corev1.KeyToPath{{Key: "server.profile.enabled", Path: "profiler.enabled"}}, + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-cmd-params-cm"}, + Optional: ptr.To(true)}, + }, + }, + { + Name: "tmp", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + })) + + By("verifying volumemounts and volumes of Argo CD Repo server") + argocdRepoServerDepl := appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-repo-server", Namespace: randomNS.Name}} + + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(&argocdRepoServerDepl), &argocdRepoServerDepl)).To(Succeed()) + + Expect(argocdRepoServerDepl.Spec.Template.Spec.Containers[0].VolumeMounts).To(Equal([]corev1.VolumeMount{ + {Name: "ssh-known-hosts", MountPath: "/app/config/ssh"}, + {Name: "tls-certs", MountPath: "/app/config/tls"}, + {Name: "gpg-keys", MountPath: "/app/config/gpg/source"}, + {Name: "gpg-keyring", MountPath: "/app/config/gpg/keys"}, + {Name: "argocd-repo-server-tls", MountPath: "/app/config/reposerver/tls"}, + {Name: "argocd-operator-redis-tls", MountPath: "/app/config/reposerver/tls/redis"}, + {Name: "plugins", MountPath: "/home/argocd/cmp-server/plugins"}, + {Name: "tmp", MountPath: "/tmp"}, + })) + + Expect(argocdRepoServerDepl.Spec.Template.Spec.Volumes).To(Equal([]corev1.Volume{ + { + Name: "ssh-known-hosts", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-ssh-known-hosts-cm"}}, + }, + }, + { + Name: "tls-certs", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-tls-certs-cm"}}, + }, + }, + { + Name: "gpg-keys", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-gpg-keys-cm"}}, + }, + }, + { + Name: "gpg-keyring", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "argocd-repo-server-tls", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: ptr.To(int32(420)), + SecretName: "argocd-repo-server-tls", + Optional: ptr.To(true), + }, + }, + }, + { + Name: "argocd-operator-redis-tls", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: ptr.To(int32(420)), + SecretName: "argocd-operator-redis-tls", + Optional: ptr.To(true), + }, + }, + }, + { + Name: "var-files", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "plugins", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "tmp", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + })) + + By("verifying volumemounts and volumes of Argo CD Application controller") + applControllerSS := appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: argoCDRandomNS.Namespace}} + + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(&applControllerSS), &applControllerSS)).To(Succeed()) + + Expect(applControllerSS.Spec.Template.Spec.Containers[0].VolumeMounts).To(Equal([]corev1.VolumeMount{ + {Name: "argocd-repo-server-tls", MountPath: "/app/config/controller/tls"}, + {Name: "argocd-operator-redis-tls", MountPath: "/app/config/controller/tls/redis"}, + {Name: "argocd-home", MountPath: "/home/argocd"}, + {Name: "argocd-cmd-params-cm", MountPath: "/home/argocd/params"}, + {Name: "argocd-application-controller-tmp", MountPath: "/tmp"}, + })) + + Expect(applControllerSS.Spec.Template.Spec.Volumes).To(Equal([]corev1.Volume{ + { + Name: "argocd-repo-server-tls", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: ptr.To(int32(420)), + SecretName: "argocd-repo-server-tls", + Optional: ptr.To(true), + }, + }, + }, + { + Name: "argocd-operator-redis-tls", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: ptr.To(int32(420)), + SecretName: "argocd-operator-redis-tls", + Optional: ptr.To(true), + }, + }, + }, + { + Name: "argocd-home", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "argocd-cmd-params-cm", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + Items: []corev1.KeyToPath{{Key: "controller.profile.enabled", Path: "profiler.enabled"}}, + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-cmd-params-cm"}, + Optional: ptr.To(true)}, + }, + }, + { + Name: "argocd-application-controller-tmp", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + })) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-021_validate_rolebindings_test.go b/test/openshift/e2e/ginkgo/parallel/1-021_validate_rolebindings_test.go new file mode 100644 index 000000000..c03f41944 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-021_validate_rolebindings_test.go @@ -0,0 +1,83 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-021_validate_rolebindings", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies a namespace-scoped Argo CD instance has the expected RoleBindings", func() { + + By("creating new namespace-scoped Argo CD instance and verifying it becomes available") + randomNS, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: randomNS.Name}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying expected RoleBindings exist and have the expected contents") + rbsToCheck := []string{ + "argocd-argocd-application-controller", + "argocd-argocd-redis-ha", + "argocd-argocd-server", + } + for _, rbName := range rbsToCheck { + rb := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: rbName, Namespace: argoCD.Namespace}} + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(rb), rb)).To(Succeed()) + + Expect(rb.RoleRef.APIGroup).To(Equal("rbac.authorization.k8s.io")) + Expect(rb.RoleRef.Kind).To(Equal("Role")) + Expect(rb.RoleRef.Name).To(Equal(rbName), "RoleBinding and ServiceAccount have the same name") + + Expect(rb.Subjects).To(HaveLen(1)) + Expect(rb.Subjects[0].Kind).To(Equal("ServiceAccount")) + Expect(rb.Subjects[0].Name).To(Equal(rbName)) + } + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-023_validate_repo_server_tls_test.go b/test/openshift/e2e/ginkgo/parallel/1-023_validate_repo_server_tls_test.go new file mode 100644 index 000000000..f2c6e9723 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-023_validate_repo_server_tls_test.go @@ -0,0 +1,143 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "reflect" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + appFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-023_validate_repo_server_tls", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifying ArgoCD .spec.repo AutoTLS and verifyTLS work as expected", func() { + + By("creating a namespace scoped Argo instance with AutoTLS set to 'openshift'") + + nsTest_1_23_custom, cleanupFn1 := fixture.CreateNamespaceWithCleanupFunc("test-1-23-custom") + defer cleanupFn1() + + argoCDTest_1_23_custom := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: nsTest_1_23_custom.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Repo: argov1beta1api.ArgoCDRepoSpec{ + AutoTLS: "openshift", + }, + }, + } + Expect(k8sClient.Create(ctx, argoCDTest_1_23_custom)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and ready, and verifying the expected Secret exists") + Eventually(argoCDTest_1_23_custom, "3m", "5s").Should(argocdFixture.BeAvailable()) + + argocdRepoServerTLSSecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "argocd-repo-server-tls", Namespace: nsTest_1_23_custom.Name}} + Eventually(argocdRepoServerTLSSecret).Should(k8sFixture.ExistByName()) + + By("enabling verifyTLS in the ArgoCD instance, and checking that the argocd-server Deployment has expected parameters") + argocdFixture.Update(argoCDTest_1_23_custom, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.VerifyTLS = true + }) + + Eventually(func() bool { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: nsTest_1_23_custom.Name}} + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(depl), depl); err != nil { + GinkgoWriter.Println(err) + return false + } + + if len(depl.Spec.Template.Spec.Containers) == 0 { + return false + } + + cmdList := depl.Spec.Template.Spec.Containers[0].Command + + return reflect.DeepEqual(cmdList, []string{ + "argocd-server", + "--repo-server-strict-tls", + "--staticassets", + "/shared/app", + "--dex-server", + "https://argocd-dex-server.test-1-23-custom.svc.cluster.local:5556", + "--repo-server", + "argocd-repo-server.test-1-23-custom.svc.cluster.local:8081", + "--redis", + "argocd-redis.test-1-23-custom.svc.cluster.local:6379", + "--loglevel", + "info", + "--logformat", + "text", + }) + + }).Should(BeTrue()) + + By("ensuring we can deploy to the namespace via the ArgoCD instance") + app := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "guestbook", Namespace: nsTest_1_23_custom.Name}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "./test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: nsTest_1_23_custom.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + Retry: &argocdv1alpha1.RetryStrategy{Limit: int64(5)}, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + Eventually(app, "60s", "1s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app, "60s", "1s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-025-validate-managed-by-change_test.go b/test/openshift/e2e/ginkgo/parallel/1-025-validate-managed-by-change_test.go new file mode 100644 index 000000000..85a28626d --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-025-validate-managed-by-change_test.go @@ -0,0 +1,167 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + appFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + namespaceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/namespace" + rolebindingFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/rolebinding" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-025-validate-managed-by-change", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensuring that managed-by label can transition between two different Argo CD instances", func() { + + By("creating 3 namespaces: 2 contain argo cd instances, and one will be managed by one of those namespaces") + + test_1_25_argo1NS, cleanup1 := fixture.CreateNamespaceWithCleanupFunc("test-1-25-argo1") + defer cleanup1() + + test_1_25_argo2NS, cleanup2 := fixture.CreateNamespaceWithCleanupFunc("test-1-25-argo2") + defer cleanup2() + + test_1_25_targetNS, cleanup3 := fixture.CreateManagedNamespaceWithCleanupFunc("test-1-25-target", test_1_25_argo1NS.Name) + defer cleanup3() + + argoCDtest_1_25_argo1 := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: test_1_25_argo1NS.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCDtest_1_25_argo1)).To(Succeed()) + + argoCDtest_1_25_argo2 := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: test_1_25_argo2NS.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCDtest_1_25_argo2)).To(Succeed()) + + By("waiting for ArgoCD CRs to be reconciled and the instances to be ready") + Eventually(argoCDtest_1_25_argo1, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCDtest_1_25_argo2, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("ensuring we can deploy to the managed namespace via the ArgoCD instance in first namespace") + app := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "guestbook", Namespace: argoCDtest_1_25_argo1.Namespace}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "./test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: test_1_25_targetNS.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + Retry: &argocdv1alpha1.RetryStrategy{Limit: int64(5)}, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("waiting for all pods to be ready in both Argo CD namespaces") + fixture.WaitForAllPodsInTheNamespaceToBeReady(test_1_25_argo1NS.Name, k8sClient) + fixture.WaitForAllPodsInTheNamespaceToBeReady(test_1_25_argo2NS.Name, k8sClient) + + By("verifying Argo CD Application deployed as expected and is healthy and synced") + Eventually(app, "3m", "5s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app, "60s", "5s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + By("update 'test_1_25_target' NS to be managed by the second Argo CD instance, rather than the first") + namespaceFixture.Update(&test_1_25_targetNS, func(n *corev1.Namespace) { + n.Labels["argocd.argoproj.io/managed-by"] = "test-1-25-argo2" + }) + + By("verifying that RoleBinding in 'test_1_25_target' is updated to the second namespace") + roleBindingIntest_1_25_targetNS := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: test_1_25_targetNS.Name}} + Eventually(roleBindingIntest_1_25_targetNS).Should(rolebindingFixture.HaveSubject(rbacv1.Subject{ + Kind: "ServiceAccount", + Name: "argocd-argocd-application-controller", + Namespace: "test-1-25-argo2", + })) + + By("hard refresh the Application, to pick up changes") + appFixture.Update(app, func(a *argocdv1alpha1.Application) { + if a.Annotations == nil { + a.Annotations = map[string]string{} + } + a.Annotations["argocd.argoproj.io/refresh"] = "hard" + }) + + By("creating a new Argo CD Application in second Argo CD namespace") + app_argo2 := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "guestbook", Namespace: argoCDtest_1_25_argo2.Namespace}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "./test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: test_1_25_targetNS.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + Retry: &argocdv1alpha1.RetryStrategy{Limit: int64(5)}, + }, + }, + } + Expect(k8sClient.Create(ctx, app_argo2)).To(Succeed()) + + By("First Argo CD instance Application should be unhealthy, because it is no longer managing the namespace") + Eventually(app, "4m", "1s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusMissing)) + Eventually(app, "4m", "1s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeUnknown)) + + By("Second Argo CD instance Application should be healthy, because it is now managing the namespace") + Eventually(app_argo2, "60s", "1s").Should(appFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app_argo2, "60s", "1s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-029_validate_tls_secret_no_scale_test.go b/test/openshift/e2e/ginkgo/parallel/1-029_validate_tls_secret_no_scale_test.go new file mode 100644 index 000000000..04851fd3f --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-029_validate_tls_secret_no_scale_test.go @@ -0,0 +1,116 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "time" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + secretFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/secret" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-029_validate_tls_secret_no_scale", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that Argo CD server becomes ready after modifying Argo CD Server TLS secret", func() { + + By("creating basic Argo CD instance") + argoCDNS, cleanup1 := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanup1() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: argoCDNS.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready, and that argocd-tls secret exists") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + argoCDTLSSecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "argocd-tls", Namespace: argoCDNS.Name}} + Eventually(argoCDTLSSecret).Should(k8sFixture.ExistByName()) + + By("modifying the argocd-tls Secret with a name TLS cert/key generated by openssl") + output, err := osFixture.ExecCommandWithOutputParam(false, "openssl", "req", "-x509", "-newkey", "rsa:4096", "-keyout", "/tmp/test-029-key.pem", "-out", "/tmp/test-029-cert.pem", "-subj", "/CN=test-029-cert", "-days", "365", "-nodes") + if err != nil { + GinkgoWriter.Println(output) + } + + Expect(err).ToNot(HaveOccurred()) + + certValue, err := osFixture.ExecCommandWithOutputParam(false, "bash", "-c", "cat /tmp/test-029-cert.pem | base64 -w 0") + if err != nil { + GinkgoWriter.Println(certValue) + } + Expect(err).ToNot(HaveOccurred()) + + keyValue, err := osFixture.ExecCommandWithOutputParam(false, "bash", "-c", "cat /tmp/test-029-key.pem | base64 -w 0") + if err != nil { + GinkgoWriter.Println(keyValue) + } + Expect(err).ToNot(HaveOccurred()) + + secretFixture.Update(argoCDTLSSecret, func(s *corev1.Secret) { + s.Data = map[string][]byte{ + "tls.key": ([]byte)(keyValue), + "tls.crt": ([]byte)(certValue), + } + }) + + // Unfortunately we need to use time.sleep, as there is no other way to verify that Argo CD operator has reconciled the TLS Secret + By("waiting 30 seconds to ensure that Argo CD operator has had a chance to reconcile the TLS Secret change") + time.Sleep(30 * time.Second) + + By("verifying Argo CD server becomes ready") + argoCDDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: argoCDNS.Name}} + Eventually(argoCDDepl).Should(k8sFixture.ExistByName()) + Eventually(argoCDDepl, "120s", "1s").Should(deploymentFixture.HaveReadyReplicas(1)) + Eventually(argoCDDepl).Should(deploymentFixture.HaveReplicas(1)) + Eventually(argoCDDepl).Should(deploymentFixture.HaveUpdatedReplicas(1)) + + By("verifying Argo CD server does not change after becoming ready") + Consistently(argoCDDepl, "30s", "1s").Should(deploymentFixture.HaveObservedGeneration(1)) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-030_validate_reencrypt_test.go b/test/openshift/e2e/ginkgo/parallel/1-030_validate_reencrypt_test.go new file mode 100644 index 000000000..a22911fe2 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-030_validate_reencrypt_test.go @@ -0,0 +1,169 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "crypto/tls" + "io" + "net/http" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + routeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/route" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-030_validate_reencrypt", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies Argo CD Server's Route can be enabled with TLSTerminationReencrypt", func() { + + By("creating namespace-scoped Argo CD instance with rencrypt Route") + + test_1_30_argo1, cleanupFunc := fixture.CreateNamespaceWithCleanupFunc("test-1-30-argo1") + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: test_1_30_argo1.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + TLS: &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying Argo CD Server's Route has the expected values") + r := &routev1.Route{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: test_1_30_argo1.Name}} + Eventually(r).Should(k8sFixture.ExistByName()) + + Expect(r).Should(routeFixture.HavePort(intstr.FromString("https"))) + Expect(r).Should(routeFixture.HaveTLS(routev1.TLSTerminationReencrypt, routev1.InsecureEdgeTerminationPolicyRedirect)) + Expect(r).Should(routeFixture.HaveTo(routev1.RouteTargetReference{Kind: "Service", Name: "argocd-server", Weight: ptr.To(int32(100))})) + + By("verifying the Route was successfully admitted, and ths TLS Secret exists") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(r), r); err != nil { + GinkgoWriter.Println(err) + return false + } + + ingressSlice := r.Status.Ingress + if ingressSlice == nil || len(ingressSlice) != 1 { + return false + } + + ingress := ingressSlice[0] + + if ingress.Conditions == nil || len(ingress.Conditions) != 1 { + return false + } + + condition := ingress.Conditions[0] + + return condition.Status == "True" && condition.Type == routev1.RouteAdmitted + + }).Should(BeTrue(), ".status.ingress.conditions[0] should have status:true and type:admitted") + + secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server-tls", Namespace: test_1_30_argo1.Name}} + Eventually(secret).Should(k8sFixture.ExistByName()) + + fixture.WaitForAllPodsInTheNamespaceToBeReady(test_1_30_argo1.Name, k8sClient) + + By("verify we can access the route, and it contains a specific expected string") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(r), r); err != nil { + GinkgoWriter.Println("Error on retrieving route:", err) + return false + } + + if len(r.Status.Ingress) == 0 { + return false + } + + host := r.Status.Ingress[0].Host + + // Create a custom HTTP transport + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, // Disable TLS certificate verification + }, + } + + // Create an HTTP client with the custom transport + client := &http.Client{Transport: tr} + + // Make a GET request + resp, err := client.Get("https://" + host) + if err != nil { + GinkgoWriter.Println("Error:", err) + return false + } + defer resp.Body.Close() + + // Read the response body + body, err := io.ReadAll(resp.Body) + if err != nil { + GinkgoWriter.Println("Error reading body:", err) + return false + } + + // Print the response body + GinkgoWriter.Println(string(body)) + + return strings.Contains(string(body), "Your browser does not support JavaScript.") + + }, "90s", "5s").Should(BeTrue()) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-031_validate_toolchain_test.go b/test/openshift/e2e/ginkgo/parallel/1-031_validate_toolchain_test.go new file mode 100644 index 000000000..ab9775227 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-031_validate_toolchain_test.go @@ -0,0 +1,190 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "os" + + // "os" + + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-031_validate_toolchain", func() { + + var ( + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + }) + + // getPodName waits for there to exist a running pod with name 'name' in openshift-gitops + getPodName := func(name string) (string, error) { + + var podName string + + if err := wait.PollUntilContextTimeout(context.Background(), time.Second*5, time.Minute*2, true, func(ctx context.Context) (done bool, err error) { + + var podList corev1.PodList + if err := k8sClient.List(ctx, &podList, client.InNamespace("openshift-gitops")); err != nil { + GinkgoWriter.Println(err) + return false, nil + } + + for _, pod := range podList.Items { + if pod.Status.Phase == corev1.PodRunning { + if strings.Contains(pod.Name, name) { + podName = pod.Name + return true, nil + } + } + } + return false, nil + + }); err != nil { + return "", err + } + + return podName, nil + } + + It("verifies that toolchain versions have the expected values", func() { + + // These variables need to be maintained according to the component matrix: https://spaces.redhat.com/display/GITOPS/GitOps+Component+Matrix + expected_kustomizeVersion := "v5.4.3" + expected_helmVersion := "v3.16.3" + expected_argocdVersion := "v2.14.4" + + var expected_dexVersion string + var expected_redisVersion string + + if os.Getenv("CI") == "prow" { + // when running against openshift-ci + expected_dexVersion = "v2.30.3-dirty" + expected_redisVersion = "6.2.4" + + } else { + // when running against RC/ released version of gitops + expected_dexVersion = "v2.35.1" + expected_redisVersion = "6.2.7" + } + + By("locating pods containing toolchain in openshift-gitops") + + gitops_server_pod, err := getPodName("openshift-gitops-server") + Expect(err).ToNot(HaveOccurred()) + dex_pod, err := getPodName("openshift-gitops-dex-server") + Expect(err).ToNot(HaveOccurred()) + redis_pod, err := getPodName("openshift-gitops-redis") + Expect(err).ToNot(HaveOccurred()) + + serverRoute := &routev1.Route{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-server", Namespace: "openshift-gitops"}} + Eventually(serverRoute).Should(k8sFixture.ExistByName()) + + By("extracting the kustomize version from container") + + kustomizeVersion, err := osFixture.ExecCommand("bash", "-c", "oc -n openshift-gitops exec "+gitops_server_pod+" -- kustomize version") + + Expect(err).NotTo(HaveOccurred()) + kustomizeVersion = strings.TrimSpace(kustomizeVersion) + + By("extracting the helm version from container") + helmVersion, err := osFixture.ExecCommand("bash", "-c", "oc -n openshift-gitops exec "+gitops_server_pod+" -- helm version") + Expect(err).NotTo(HaveOccurred()) + + // output format: + // version.BuildInfo{Version:"v3.15.4", GitCommit:"fa9efb07d9d8debbb4306d72af76a383895aa8c4", GitTreeState:"", GoVersion:"go1.22.9 (Red Hat 1.22.9-1.module+el8.10.0+22500+aee717ef)" + helmVersion = helmVersion[strings.Index(helmVersion, "Version:"):] + // After: Version:"v3.15.4" (...) + helmVersion = helmVersion[strings.Index(helmVersion, "\"")+1:] + // After: v3.15.4" (...) + helmVersion = helmVersion[:strings.Index(helmVersion, "\"")] + // After: v3.15.4 + + By("extracting the argo cd server version from container") + argocdVersion, err := osFixture.ExecCommand("bash", "-c", "oc -n openshift-gitops exec "+gitops_server_pod+" -- argocd version --short --server "+serverRoute.Spec.Host+" --insecure | grep 'argocd-server'") + argocdVersion = strings.ReplaceAll(argocdVersion, "+unknown", "") + // output format: + // argocd-server: v2.13.1+af54ef8 + Expect(err).NotTo(HaveOccurred()) + + By("extracting the dex version from container") + dexVersionOutput, err := osFixture.ExecCommand("bash", "-c", "oc -n openshift-gitops exec "+dex_pod+" -- dex version") + Expect(err).ToNot(HaveOccurred()) + // Output format: + // Defaulted container "dex" out of: dex, copyutil (init) + // Dex Version: v2.41.1-1-ga7854d65 + + var dexVersion string + dexVersionOutputSplit := strings.Split(dexVersionOutput, "\n") + for _, line := range dexVersionOutputSplit { + if strings.Contains(line, "Dex Version:") { + dexVersion = line + dexVersion = dexVersion[strings.Index(dexVersion, ":")+1:] + // After: ' v2.41.1-1-ga7854d65' + dexVersion = strings.TrimSpace(dexVersion) + // After: 'v2.41.1-1-ga7854d65' + break + } + } + Expect(dexVersion).ToNot(BeEmpty()) + + By("extracting the redis version from container") + redisVersion, err := osFixture.ExecCommand("bash", "-c", "oc -n openshift-gitops exec "+redis_pod+" -- redis-server -v") + // output format: Redis server v=6.2.7 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=5d88ce217879027a + redisVersion = redisVersion[strings.Index(redisVersion, "v=")+2:] + // After: v=6.2.7 (...) + redisVersion = redisVersion[0:strings.Index(redisVersion, " ")] + // After: v=6.2.7 + Expect(err).NotTo(HaveOccurred()) + + By("verifying containers have expected toolchain versions") + + Expect(kustomizeVersion).To(Equal(expected_kustomizeVersion)) + Expect(helmVersion).To(Equal(expected_helmVersion)) + Expect(dexVersion).To(Equal(expected_dexVersion)) + + // We are as argocdVersion contains v2.7.6+00c914a suffix addition to the version no. + // So, we are checking if expected_argocdVersion is substring of the actual version + Expect(argocdVersion).To(ContainSubstring(expected_argocdVersion)) + + Expect(redisVersion).To(Equal(expected_redisVersion)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-032_validate_resource_inclusions_test.go b/test/openshift/e2e/ginkgo/parallel/1-032_validate_resource_inclusions_test.go new file mode 100644 index 000000000..21106fec0 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-032_validate_resource_inclusions_test.go @@ -0,0 +1,91 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-032_validate_resource_inclusions", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies setting resource inclusion on the ArgoCD CR will cause it to be set on Argo CD ConfigMap", func() { + + By("creating namespace-scoped Argo CD instance") + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + // 01-assert.yaml + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("adding resource inclusion to ArgoCD CR") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.ResourceInclusions = `- apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - DaemonSet` + }) + + argocdCM := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns.Name}} + + By("verifying ConfigMap has same resource inclusion value as specified in ArgoCD CR") + Eventually(argocdCM).Should(configmapFixture.HaveStringDataKeyValue("resource.inclusions", `- apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - DaemonSet`), + ) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-033_validate_resource_exclusions_test.go b/test/openshift/e2e/ginkgo/parallel/1-033_validate_resource_exclusions_test.go new file mode 100644 index 000000000..17fa88da5 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-033_validate_resource_exclusions_test.go @@ -0,0 +1,89 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-033_validate_resource_exclusions", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies setting resource exclusion on the ArgoCD CR will cause it to be set on Argo CD ConfigMap", func() { + + By("creating namespace-scoped Argo CD instance") + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.ResourceExclusions = `- apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - DaemonSet` + }) + + argocdConfigMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns.Name}} + + By("verifying ConfigMap has same resource exclusion value as specified in ArgoCD CR") + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("resource.exclusions", `- apiGroups: + - tekton.dev + clusters: + - '*' + kinds: + - DaemonSet`), + ) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-036_validate_keycloak_resource_reqs_test.go b/test/openshift/e2e/ginkgo/parallel/1-036_validate_keycloak_resource_reqs_test.go new file mode 100644 index 000000000..4b19d55f8 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-036_validate_keycloak_resource_reqs_test.go @@ -0,0 +1,137 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deplFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + ssFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-036_validate_keycloak_resource_reqs", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that Keycloak SSO can be enabled", func() { + + By("creating namespace-scoped Argo CD instance") + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + expectEverythingIsRunning := func() { + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("ensuring all expected Deployments and StatefulSets are running") + deploymentsShouldExist := []string{"argocd-redis", "argocd-server", "argocd-repo-server"} + for _, depl := range deploymentsShouldExist { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: depl, Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deplFixture.HaveReplicas(1)) + Eventually(depl).Should(deplFixture.HaveReadyReplicas(1)) + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(statefulSet).Should(ssFixture.HaveReplicas(1)) + Eventually(statefulSet).Should(ssFixture.HaveReadyReplicas(1)) + + } + + expectEverythingIsRunning() + + By("set .spec.SSO.provider = keycloak") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.SSO = &argov1beta1api.ArgoCDSSOSpec{ + Provider: "keycloak", + } + }) + + By("verifying keycloak-1-deploy pod should be created") + pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "keycloak-1-deploy", Namespace: ns.Name}} + Eventually(pod).Should(k8sFixture.ExistByName()) + + By("verifying keycloak-1-deploy pod should successfully complete") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(pod), pod); err != nil { + GinkgoWriter.Println(err) + return false + } + + matchFound := false + for _, item := range pod.Status.ContainerStatuses { + if item.Name == "deployment" { + GinkgoWriter.Println("Pod keycloak-1-deploy status has terminated status:", item.State.Terminated) + if item.State.Terminated != nil && item.State.Terminated.Reason == "Completed" { + matchFound = true + } + } + } + return matchFound + + }, "4m", "2s").Should(BeTrue()) + + By("verifying all other Argo CD components should be successfully running") + expectEverythingIsRunning() + + By("verifying keycloak-1-deploy has expected requests/limits") + pod = &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "keycloak-1-deploy", Namespace: ns.Name}} + Eventually(pod).Should(k8sFixture.ExistByName()) + + podContainerResources := pod.Spec.Containers[0].Resources + + Expect(podContainerResources.Limits.Cpu().AsDec().String()).To(Equal("0.500")) + Expect(podContainerResources.Limits.Memory().AsDec().String()).To(Equal("536870912")) // 512MiB + Expect(podContainerResources.Requests.Cpu().AsDec().String()).To(Equal("0.250")) + Expect(podContainerResources.Requests.Memory().AsDec().String()).To(Equal("268435456")) // 256MiB + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-037_validate_argocd_setting_replicas_test.go b/test/openshift/e2e/ginkgo/parallel/1-037_validate_argocd_setting_replicas_test.go new file mode 100644 index 000000000..45672ffa0 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-037_validate_argocd_setting_replicas_test.go @@ -0,0 +1,99 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deplFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-037_validate_argocd_setting_replicas", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that setting repo/server replicas in ArgoCD .spec will set them in repo/server Deployment", func() { + By("creating namespace-scoped Argo CD instance") + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("updating server and repo replicas to 3") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.Replicas = ptr.To((int32)(3)) + }) + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.Replicas = ptr.To((int32)(3)) + }) + + By("verifying 3 server and repo replicas become ready") + serverDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: ns.Name}} + Eventually(serverDepl, "60s", "1s").Should(deplFixture.HaveReadyReplicas(3)) + + repoDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-repo-server", Namespace: ns.Name}} + Eventually(repoDepl, "60s", "1s").Should(deplFixture.HaveReadyReplicas(3)) + + By("updating server and repo replicas to 1") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.Replicas = ptr.To((int32)(1)) + }) + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.Replicas = ptr.To((int32)(1)) + }) + + By("verifying 1 server and repo replicas become ready") + Eventually(serverDepl, "60s", "1s").Should(deplFixture.HaveReadyReplicas(1)) + + Eventually(repoDepl, "60s", "1s").Should(deplFixture.HaveReadyReplicas(1)) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-038_validate_productized_images_test.go b/test/openshift/e2e/ginkgo/parallel/1-038_validate_productized_images_test.go new file mode 100644 index 000000000..5ac35e6b7 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-038_validate_productized_images_test.go @@ -0,0 +1,109 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "fmt" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-038_validate_productized_images", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that Argo CD components are based on registry.redhat.io images", func() { + + if fixture.EnvNonOLM() { + Skip("skipping test as NON_OLM env is set. This test requires registry.redhat.io images, which are installed via OLM") + return + } + + if fixture.EnvLocalRun() { + Skip("skipping test as LOCAL_RUN env is set. This test requires registry.redhat.io images, which are installed via OLM") + return + } + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + expectPodHasRedHatImage := func(name string, template corev1.PodTemplateSpec) { + + By("verifying the Deployment/StatefulSet " + name + " has a registry.redhat.io image") + for _, container := range template.Spec.Containers { + + if !strings.Contains(container.Image, "registry.redhat.io/openshift-gitops-1/argocd-rhel") { + msg := fmt.Sprintln("Non-productized image in workload", name, "detected.") + + if !fixture.EnvCI() { + Fail(msg) + } else { + GinkgoWriter.Println(msg) + } + } + } + } + + deployments := []string{"argocd-server", "argocd-repo-server"} + for _, deployment := range deployments { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deployment, Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + expectPodHasRedHatImage(depl.Name, depl.Spec.Template) + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + expectPodHasRedHatImage(statefulSet.Name, statefulSet.Spec.Template) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-039_validate_fix_argocd-tls-certs-cm_test.go b/test/openshift/e2e/ginkgo/parallel/1-039_validate_fix_argocd-tls-certs-cm_test.go new file mode 100644 index 000000000..8710f81a4 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-039_validate_fix_argocd-tls-certs-cm_test.go @@ -0,0 +1,113 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-039_validate_fix_argocd-tls-certs-cm", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that setting an invalid TLS certificate on ArgoCD CR does not replace a valid certificate on TLS ConfigMap", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("modifying argocd-tls-certs-cm to add valid, empty certificate") + + tlsCertsConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-tls-certs-cm", Namespace: ns.Name}, + } + Eventually(tlsCertsConfigMap).Should(k8sFixture.ExistByName()) + + configmapFixture.Update(tlsCertsConfigMap, func(cm *corev1.ConfigMap) { + if cm.Data == nil { + cm.Data = map[string]string{} + } + cm.Data["test.example.com"] = "-----BEGIN CERTIFICATE----- -----END CERTIFICATE-----" + }) + + By("adding invalid certificate to ArgoCD CR") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.TLS.InitialCerts = map[string]string{"test.example.com": "BEGIN CERTIFICATE"} + }) + + By("verifying that invalid certificate from ArgoCD never replaces the 'valid' ConfigMap certificate") + + Consistently(func() bool { + + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(tlsCertsConfigMap), tlsCertsConfigMap); err != nil { + GinkgoWriter.Println(err) + return true + } + + if tlsCertsConfigMap.Data == nil { + return true + } + + val := tlsCertsConfigMap.Data["test.example.com"] + GinkgoWriter.Println("ConfigMap value:", val) + return val != "BEGIN CERTIFICATE" + + }).Should(BeTrue()) + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-042_validate_status_host_test.go b/test/openshift/e2e/ginkgo/parallel/1-042_validate_status_host_test.go new file mode 100644 index 000000000..b42e741fa --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-042_validate_status_host_test.go @@ -0,0 +1,113 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + routeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/route" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-042_validate_status_host", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that .status.host of ArgoCD matches .spec.host of Route, and status is updated when Route is removed", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + serverRoute := &routev1.Route{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-server", Namespace: ns.Name}} + Eventually(serverRoute).Should(k8sFixture.ExistByName()) + + By("verifying .spec.host of Route equals .status.host of ArgoCD") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(serverRoute), serverRoute); err != nil { + GinkgoWriter.Println(err) + return false + } + + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(argoCD), argoCD); err != nil { + GinkgoWriter.Println(err) + return false + } + GinkgoWriter.Println("----") + GinkgoWriter.Println("route URL", serverRoute.Spec.Host) + GinkgoWriter.Println("status URL", argoCD.Status.Host) + + return serverRoute.Spec.Host == argoCD.Status.Host + + }).Should(BeTrue()) + + By("updating host of Route and verifying it is updated in ArgoCD cR") + routeFixture.Update(serverRoute, func(r *routev1.Route) { + r.Spec.Host = "modified-route" + }) + + Eventually(argoCD).Should(argocdFixture.HaveHost("modified-route")) + + By("disabling server Route") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.Route.Enabled = false + }) + + By("verifying Route host is removed from ArgoCD .status.host") + Eventually(argoCD).ShouldNot(argocdFixture.HaveHost("modified-route")) + Consistently(argoCD).ShouldNot(argocdFixture.HaveHost("modified-route")) + Eventually(argoCD).Should(argocdFixture.HavePhase("Available")) + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-043_validate_log_level_format_test.go b/test/openshift/e2e/ginkgo/parallel/1-043_validate_log_level_format_test.go new file mode 100644 index 000000000..1aa886a5f --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-043_validate_log_level_format_test.go @@ -0,0 +1,122 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-043_validate_log_level_format", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies ArgoCD .spec loglevel/logformat fields are set on corresponding Deployment/StatefulSet", func() { + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("enabling debug loglevel and json logformat on various Argo CD workloads") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.LogLevel = "debug" + ac.Spec.Server.LogFormat = "json" + ac.Spec.Repo.LogLevel = "debug" + ac.Spec.Repo.LogFormat = "json" + ac.Spec.Controller.LogLevel = "debug" + ac.Spec.Controller.LogFormat = "json" + }) + + // Ensure the given PodTemplate has the expected loglevel/logformat settings + podTemplateHasLogSettings := func(name string, template corev1.PodTemplateSpec) bool { + + container := template.Spec.Containers[0] + + containerCommand := strings.Join(container.Command, " ") + + GinkgoWriter.Println(name, "has container command:", containerCommand) + return strings.Contains(containerCommand, "--loglevel debug") && strings.Contains(containerCommand, "--logformat json") + } + + deployments := []string{"argocd-server", "argocd-repo-server"} + for _, deployment := range deployments { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deployment, Namespace: ns.Name}} + + By("verifying the Deployment " + depl.Name + " has expected log settings") + + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(depl), depl); err != nil { + GinkgoWriter.Println(err) + return false + } + return podTemplateHasLogSettings(depl.Name, depl.Spec.Template) + }, "60s", "1s").Should(BeTrue()) + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + By("verifying the StatefulSet " + statefulSet.Name + " has expected log settings") + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(statefulSet), statefulSet); err != nil { + GinkgoWriter.Println(err) + return false + } + + return podTemplateHasLogSettings(statefulSet.Name, statefulSet.Spec.Template) + }).Should(BeTrue()) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-044_validate_resource_limit_changes_test.go b/test/openshift/e2e/ginkgo/parallel/1-044_validate_resource_limit_changes_test.go new file mode 100644 index 000000000..b1c6565ca --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-044_validate_resource_limit_changes_test.go @@ -0,0 +1,152 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-044_validate_resource_limit_changes", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that updating resource/limit field of ArgoCD updates the corresponding resource/limit of Deployment/StatefulSet", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("200Mi"), + }, + }, + }, + Controller: argov1beta1api.ArgoCDApplicationControllerSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("2000Mi"), + }, + }, + }, + Repo: argov1beta1api.ArgoCDRepoSpec{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("200Mi"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("200Mi"), + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("updating CPU limit to 2 on every component") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + argoCD.Spec.Server.Resources.Limits[corev1.ResourceCPU] = resource.MustParse("2") + argoCD.Spec.Controller.Resources.Limits[corev1.ResourceCPU] = resource.MustParse("2") + argoCD.Spec.Repo.Resources.Limits[corev1.ResourceCPU] = resource.MustParse("2") + }) + + // Ensure the given PodTemplate has the expected CPUs + podTemplateHasCPUs := func(name string, template corev1.PodTemplateSpec) bool { + + container := template.Spec.Containers[0] + + cpu := container.Resources.Limits.Cpu().String() + + GinkgoWriter.Println("PodTemplate", name, "has CPU limit", cpu) + return cpu == "2" + } + + deployments := []string{"argocd-server", "argocd-repo-server"} + for _, deployment := range deployments { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deployment, Namespace: ns.Name}} + + By("verifying the Deployment " + depl.Name + " has expected CPU limit") + + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(depl), depl); err != nil { + GinkgoWriter.Println(err) + return false + } + return podTemplateHasCPUs(depl.Name, depl.Spec.Template) + }, "60s", "1s").Should(BeTrue()) + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + By("verifying the StatefulSet " + statefulSet.Name + " has expected CPU limit") + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(statefulSet), statefulSet); err != nil { + GinkgoWriter.Println(err) + return false + } + + return podTemplateHasCPUs(statefulSet.Name, statefulSet.Spec.Template) + }).Should(BeTrue()) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-045_validate_repo_exec_timeout_test.go b/test/openshift/e2e/ginkgo/parallel/1-045_validate_repo_exec_timeout_test.go new file mode 100644 index 000000000..41cb1bc41 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-045_validate_repo_exec_timeout_test.go @@ -0,0 +1,82 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-045_validate_repo_exec_timeout", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that ArgoCD .spec.repo.ExecTimeout is set on argocd-repo-server Deployment", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("setting execTimeout on repo server via ArgoCD CR") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.ExecTimeout = ptr.To(300) + }) + + By("verifying that argocd-repo-server has execTimeout value we set on ArgoCD CR") + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-repo-server", Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + + Eventually(depl).Should(deployment.HaveContainerWithEnvVar("ARGOCD_EXEC_TIMEOUT", "300s", 0)) + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-047_validate_custom_env_test.go b/test/openshift/e2e/ginkgo/parallel/1-047_validate_custom_env_test.go new file mode 100644 index 000000000..3d00bfa37 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-047_validate_custom_env_test.go @@ -0,0 +1,92 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-047_validate_custom_env", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that .env field of ArgoCD will cause environment variable to be set on corresponding Deployment/StatefulSet", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("setting env vars on ArgoCD for repo, server, and controller ") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} + ac.Spec.Server.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} + ac.Spec.Controller.Env = []corev1.EnvVar{{Name: "FOO", Value: "bar"}} + }) + + deployments := []string{"argocd-server", "argocd-repo-server"} + for _, deploymentFromRange := range deployments { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deploymentFromRange, Namespace: ns.Name}} + + By("verifying the Deployment " + depl.Name + " has expected env var") + + Eventually(depl, "60s", "5s").Should(deployment.HaveContainerWithEnvVar("FOO", "bar", 0)) + } + + ss := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + By("verifying the StatefulSet " + ss.Name + " has expected env var") + Eventually(ss).Should(k8sFixture.ExistByName()) + Eventually(ss, "60s", "5s").Should(statefulset.HaveContainerWithEnvVar("FOO", "bar", 0)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-048_validate_controller_sharding_test.go b/test/openshift/e2e/ginkgo/parallel/1-048_validate_controller_sharding_test.go new file mode 100644 index 000000000..6e5ace0bc --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-048_validate_controller_sharding_test.go @@ -0,0 +1,126 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "fmt" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-048_validate_controller_sharding", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that enabling sharding with 3 replicas causes Application Controller to split to 3 replicas, and disabling reverts to 1", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("enabling sharding with 3 replicas") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Controller.Sharding = argov1beta1api.ArgoCDApplicationControllerShardSpec{ + Enabled: true, + Replicas: 3, + } + }) + + By("checking all 3 replica pods exist") + for podCount := 0; podCount <= 2; podCount++ { + pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("argocd-application-controller-%d", podCount), Namespace: ns.Name}} + Eventually(pod).Should(k8sFixture.ExistByName()) + } + + Eventually(argoCD, "2m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying REPLICAS env var is set in app controller StatefulSet") + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + var match bool + for _, env := range statefulSet.Spec.Template.Spec.Containers[0].Env { + if env.Name == "ARGOCD_CONTROLLER_REPLICAS" && env.Value == "3" { + match = true + break + } + } + Expect(match).To(BeTrue(), "StatefulSet should have expected ARGOCD_CONTROLLER_REPLICAS") + + By("disabling sharding") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Controller.Sharding = argov1beta1api.ArgoCDApplicationControllerShardSpec{ + Enabled: false, + Replicas: 3, + } + }) + + By("checking 2nd and 3rd replica pods no longer exist") + for podCount := 1; podCount <= 2; podCount++ { + pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("argocd-application-controller-%d", podCount), Namespace: ns.Name}} + Eventually(pod).ShouldNot(k8sFixture.ExistByName()) + } + + By("verifying ARGOCD_CONTROLLER_REPLICAS is no longer present in StatefulSet") + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + var replicasVarFound bool + for _, env := range statefulSet.Spec.Template.Spec.Containers[0].Env { + GinkgoWriter.Println(env) + if env.Name == "ARGOCD_CONTROLLER_REPLICAS" { + replicasVarFound = true + break + } + } + Expect(replicasVarFound).To(BeFalse(), "If sharding is disabled then the ARGOCD_CONTROLLER_REPLICAS var is not set") + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-049_validate_parallelism_limit_test.go b/test/openshift/e2e/ginkgo/parallel/1-049_validate_parallelism_limit_test.go new file mode 100644 index 000000000..c68d41f13 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-049_validate_parallelism_limit_test.go @@ -0,0 +1,92 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-049_validate_parallelism_limit", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures ArgoCD .spec.controller.parallelismLimit is set on application controller statefulset", func() { + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + ss := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: argoCD.Namespace}} + Eventually(ss).Should(k8sFixture.ExistByName()) + Eventually(ss).Should(statefulsetFixture.HaveReplicas(1)) + Eventually(ss).Should(statefulsetFixture.HaveReadyReplicas(1)) + + By("waiting for Application Controller statefulset to have expected default parallelism limit") + Eventually(ss, "30s", "1s").Should(statefulsetFixture.HaveContainerCommandSubstring("-kubectl-parallelism-limit 10", 0)) + + By("updating parallelism limit to 20 in ArgoCD CR") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Controller.ParallelismLimit = 20 + }) + + By("waiting for Application Controller statefulset to have expected new parallelism limit") + Eventually(ss, "30s", "1s").Should(statefulsetFixture.HaveContainerCommandSubstring("-kubectl-parallelism-limit 20", 0)) + + By("update parallelism limit to default in ArgoCD CR") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec = argov1beta1api.ArgoCDSpec{} + }) + + By("waiting for Application Controller statefulset to have expected default limit") + Eventually(ss, "30s", "1s").Should(statefulsetFixture.HaveContainerCommandSubstring("-kubectl-parallelism-limit 10", 0)) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-051-validate_csv_permissions_test.go b/test/openshift/e2e/ginkgo/parallel/1-051-validate_csv_permissions_test.go new file mode 100644 index 000000000..9285f52e7 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-051-validate_csv_permissions_test.go @@ -0,0 +1,57 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-051-validate_csv_permissions", func() { + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + }) + + It("verifies operator can delete resourcequotas", func() { + + if fixture.EnvNonOLM() { + Skip("Skipping test as NON_OLM env var is set. This test requires openshift-gitops operator to be installed via OLM") + return + } + + if fixture.EnvLocalRun() { + Skip("Skipping test as LOCAL_RUN env var is set. The operator service account does not exist in this case") + return + } + + By("run oc command to verify our ability to delete resourcequotas") + res, err := osFixture.ExecCommand("oc", "auth", "can-i", "delete", "resourcequotas", "-n", "openshift-gitops", "--as", "system:serviceaccount:openshift-gitops-operator:openshift-gitops-operator-controller-manager") + Expect(err).ToNot(HaveOccurred()) + Expect(strings.TrimSpace(res)).To(Equal("yes")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-052_validate_rolebinding_number_test.go b/test/openshift/e2e/ginkgo/parallel/1-052_validate_rolebinding_number_test.go new file mode 100644 index 000000000..979a8909f --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-052_validate_rolebinding_number_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2021. + +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 parallel + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + namespaceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/namespace" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-052_validate_rolebinding_number", func() { + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + }) + + It("verifies RoleBindings are added to namespace-scoped Namespace when that Namespace is managed by openshift-gitops", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + namespaceFixture.Update(&ns, func(ns *corev1.Namespace) { + ns.Labels["argocd.argoproj.io/managed-by"] = "openshift-gitops" + }) + + roleBindingList := []string{"openshift-gitops-argocd-application-controller", + "openshift-gitops-argocd-server"} + + for _, rb := range roleBindingList { + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: rb, Namespace: ns.Name}, + } + Eventually(rb, "3m", "1s").Should(k8sFixture.ExistByName()) + } + + for _, rb := range roleBindingList { + rb := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: rb, Namespace: ns.Name}, + } + Consistently(rb, "20s", "4s").Should(k8sFixture.ExistByName()) + } + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-053_validate_cluster_admin_rbac_test.go b/test/openshift/e2e/ginkgo/parallel/1-053_validate_cluster_admin_rbac_test.go new file mode 100644 index 000000000..18f609f11 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-053_validate_cluster_admin_rbac_test.go @@ -0,0 +1,52 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-053_validate_cluster_admin_rbac", func() { + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + }) + + It("validates that openshift-gitops instance has expected .spec.RBAC.policy values", func() { + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops", Namespace: "openshift-gitops"}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + Expect(strings.TrimSpace(*argoCD.Spec.RBAC.Policy)).Should(Equal("g, system:cluster-admins, role:admin\ng, cluster-admins, role:admin")) + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-054_validate_deploymentconfig_test.go b/test/openshift/e2e/ginkgo/parallel/1-054_validate_deploymentconfig_test.go new file mode 100644 index 000000000..cc34a24a6 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-054_validate_deploymentconfig_test.go @@ -0,0 +1,133 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + appv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + "github.com/argoproj/gitops-engine/pkg/sync/common" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + osappsv1 "github.com/openshift/api/apps/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + applicationFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-054_validate_deploymentconfig", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies a DeploymentConfig can be deployed by Argo CD", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("creating an Argo CD Application which will deploy a DeploymentConfig") + app := &appv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-deploymentconfig", + Namespace: ns.Name, + }, + Spec: appv1alpha1.ApplicationSpec{ + Project: "default", + Source: &appv1alpha1.ApplicationSource{ + RepoURL: "https://github.com/redhat-developer/gitops-operator", + Path: "test/examples/deploymentconfig-example", + TargetRevision: "HEAD", + }, + Destination: appv1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: ns.Name, + }, + SyncPolicy: &appv1alpha1.SyncPolicy{Automated: &appv1alpha1.SyncPolicyAutomated{}}, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("verifying Application is healthy and sync operation succeeded") + Eventually(app).Should(applicationFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app).Should(applicationFixture.HaveOperationStatePhase(common.OperationSucceeded)) + + By("verifying DeploymentConfig has 2 replicas") + dc := &osappsv1.DeploymentConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "test-deploymentconfig", Namespace: ns.Name}, + } + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dc), dc); err != nil { + GinkgoWriter.Println(err) + return false + } + return dc.Status.Replicas == 2 + }, "2m", "1s").Should(BeTrue()) + + By("updating Application to instead deploy a DeploymentConfig that has replicas: 0") + applicationFixture.Update(app, func(a *appv1alpha1.Application) { + a.Spec.Project = "default" + a.Spec.Source.Path = "test/examples/deploymentconfig-example_replica_0" + }) + + By("verifying DeploymentConfig now has 0 replicas") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(dc), dc); err != nil { + GinkgoWriter.Println(err) + return false + } + return dc.Status.Replicas == 0 + }, "2m", "1s").Should(BeTrue()) + + By("verifying Application is still healthy and operation has succeeded") + Eventually(app).Should(applicationFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app).Should(applicationFixture.HaveOperationStatePhase(common.OperationSucceeded)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-057_validate_notifications_test.go b/test/openshift/e2e/ginkgo/parallel/1-057_validate_notifications_test.go new file mode 100644 index 000000000..76c985d29 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-057_validate_notifications_test.go @@ -0,0 +1,246 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "strings" + + argov1alpha1api "github.com/argoproj-labs/argocd-operator/api/v1alpha1" + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + appv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + deplFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + ssFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-057_validate_notifications", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that NotificationsConfiguration will configure Argo CD to send email on Application create", func() { + + By("creating simple namespace-scoped Argo CD instance with notifications enabled") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Notifications: argov1beta1api.ArgoCDNotifications{ + Enabled: true, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("creating Service/Deployment that will receive SMTP and write to file") + + service := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "smtp4dev", + Namespace: ns.Name, + }, + Spec: corev1.ServiceSpec{ + Selector: map[string]string{ + "app": "smtp4dev", + }, + Ports: []corev1.ServicePort{ + {Name: "smtp", Protocol: corev1.ProtocolTCP, Port: 2525, TargetPort: intstr.FromInt(2525)}, + {Name: "http", Protocol: corev1.ProtocolTCP, Port: 80, TargetPort: intstr.FromInt(80)}, + }, + }, + } + Expect(k8sClient.Create(ctx, service)).To(Succeed()) + + depl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "smtp4dev", + Namespace: ns.Name, + Labels: map[string]string{ + "app": "smtp4dev", + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: ptr.To(int32(1)), + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "smtp4dev"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "smtp4dev", + }, + }, + Spec: corev1.PodSpec{ + Affinity: &corev1.Affinity{ + NodeAffinity: &corev1.NodeAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ + NodeSelectorTerms: []corev1.NodeSelectorTerm{ + {MatchExpressions: []corev1.NodeSelectorRequirement{{ + Key: "kubernetes.io/os", + Operator: "In", + Values: []string{ + "linux", + }, + }}}, + }, + }, + }, + }, + Containers: []corev1.Container{ + { + Name: "smtp4dev", + Image: "quay.io/openshift-gitops-test/smtplistener:multiarch", + Ports: []corev1.ContainerPort{ + {ContainerPort: int32(80)}, + {ContainerPort: int32(2525)}, + }, + }, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, depl)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "5m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying all workloads are started") + + deploymentsShouldExist := []string{"argocd-redis", "argocd-server", "argocd-repo-server", "argocd-notifications-controller", "smtp4dev"} + for _, depl := range deploymentsShouldExist { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: depl, Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deplFixture.HaveReplicas(1)) + Eventually(depl).Should(deplFixture.HaveReadyReplicas(1)) + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(statefulSet).Should(ssFixture.HaveReplicas(1)) + Eventually(statefulSet).Should(ssFixture.HaveReadyReplicas(1)) + + By("modifying NotificationsConfiguration to send email to smtp4dev pod") + + notificationsConfiguration := &argov1alpha1api.NotificationsConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default-notifications-configuration", + Namespace: ns.Name, + }, + } + k8sFixture.Update(notificationsConfiguration, func(o client.Object) { + ncObj, ok := o.(*argov1alpha1api.NotificationsConfiguration) + Expect(ok).To(BeTrue()) + + ncObj.Spec.Services = map[string]string{"service.email.gmail": "{host: smtp4dev, port: 2525, from: fake@email.com }"} + + }) + + By("waiting for operator to reconcile our change to NotificationsConfiguration CR by checking argocd-notifications-cm has expected value") + notificationConfigMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-notifications-cm", Namespace: ns.Name}} + Eventually(notificationConfigMap).Should(k8sFixture.ExistByName()) + Eventually(notificationConfigMap).Should( + configmapFixture.HaveStringDataKeyValue("service.email.gmail", "{host: smtp4dev, port: 2525, from: fake@email.com }")) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "5m", "5s").Should(argocdFixture.BeAvailable()) + + By("creating Applications with notification annotation") + app := &appv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-app-3", + Namespace: ns.Name, + Annotations: map[string]string{ + "notifications.argoproj.io/subscribe.on-created.gmail": "jdfake@email.com", + }, + }, + Spec: appv1alpha1.ApplicationSpec{ + Project: "default", + Source: &appv1alpha1.ApplicationSource{ + RepoURL: "https://github.com/jgwest/gitops-operator", + Path: "test/examples/nginx", + TargetRevision: "HEAD", + }, + Destination: appv1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: ns.Name, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("waiting for Argo CD to send an email to smtp4dev Pod indicating that the Application was created") + + podList := &corev1.PodList{} + Expect(k8sClient.List(ctx, podList, &client.ListOptions{Namespace: ns.Name})) + var smtp4DevPod *corev1.Pod + for idx := range podList.Items { + item := podList.Items[idx] + if item.Labels["app"] == "smtp4dev" { + smtp4DevPod = &item + break + } + } + Expect(smtp4DevPod).ToNot(BeNil()) + + Eventually(func() bool { + + out, err := osFixture.ExecCommand("kubectl", "-n", ns.Name, "exec", "--stdin", smtp4DevPod.Name, "--", "/bin/bash", + "-c", + "cat /tmp/*") + + GinkgoWriter.Println(out) + + if err != nil { + GinkgoWriter.Println(err) + } + + return strings.Contains(out, "Subject: Application my-app-3 has been created.") + + }, "2m", "5s").Should(BeTrue()) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-058_validate_prometheus_rule_test.go b/test/openshift/e2e/ginkgo/parallel/1-058_validate_prometheus_rule_test.go new file mode 100644 index 000000000..70eddb349 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-058_validate_prometheus_rule_test.go @@ -0,0 +1,98 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + appv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + applicationFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-058_validate_prometheus_rule_test", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("deploys bgd-k8s to namespace-scoped Argo CD and makes sure it's healthy", func() { + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + fixture.WaitForAllPodsInTheNamespaceToBeReady(ns.Name, k8sClient) + + By("creating an Argo CD Application which will deploy bgd-k8s repo") + app := &appv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1-58-custom", + Namespace: ns.Name, + }, + Spec: appv1alpha1.ApplicationSpec{ + Project: "default", + Source: &appv1alpha1.ApplicationSource{ + RepoURL: "https://github.com/redhat-developer/gitops-operator", + Path: "test/examples/bgd-k8s", + TargetRevision: "HEAD", + }, + Destination: appv1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: ns.Name, + }, + SyncPolicy: &appv1alpha1.SyncPolicy{Automated: &appv1alpha1.SyncPolicyAutomated{}}, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + Eventually(app).Should(applicationFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app).Should(applicationFixture.HaveSyncStatusCode(appv1alpha1.SyncStatusCodeSynced)) + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-061_validate_resource_tracking_method_test.go b/test/openshift/e2e/ginkgo/parallel/1-061_validate_resource_tracking_method_test.go new file mode 100644 index 000000000..12d0c1c60 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-061_validate_resource_tracking_method_test.go @@ -0,0 +1,103 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-061_validate_resource_tracking_method", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies .spec.resourceTrackingMethod can be used to configure Argo CD instance, and the value is set in argocd-cm ConfigMap", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying ArgoCD CR defaults to resourceTrackingMethod: label") + argocdConfigMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns.Name}} + Eventually(argocdConfigMap).Should(k8sFixture.ExistByName()) + + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("application.resourceTrackingMethod", "label")) + + By("verifying we can switch ArgoCD CR to resourceTrackingMethod: annotation, and the ConfigMap will be updated") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + argoCD.Spec.ResourceTrackingMethod = "annotation" + }) + + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("application.resourceTrackingMethod", "annotation")) + + By("verifying we can switch ArgoCD CR to resourceTrackingMethod: annotation+label, and the ConfigMap will be updated") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + argoCD.Spec.ResourceTrackingMethod = "annotation+label" + }) + + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("application.resourceTrackingMethod", "annotation+label")) + + By("verifying if an invalid method is specified, then the default is used") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + argoCD.Spec.ResourceTrackingMethod = "invalid_method" + }) + + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("application.resourceTrackingMethod", "label")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-062_validate_extra_config_test.go b/test/openshift/e2e/ginkgo/parallel/1-062_validate_extra_config_test.go new file mode 100644 index 000000000..2cc1e4d1c --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-062_validate_extra_config_test.go @@ -0,0 +1,170 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-062_validate_extra_config_test", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that .spec.extraConfig overrides values specified in .spec.sso.dex.config and .spec.disableAdmin", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + ExtraConfig: map[string]string{"admin.enabled": "true"}, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + argocdConfigMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns.Name}} + Eventually(argocdConfigMap).Should(k8sFixture.ExistByName()) + + By("verifying ConfigMap picks up admin.enabled setting from ArgoCD CR") + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + + By("disabling admin via CR spec, but enabling via extra config") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.DisableAdmin = true + ac.Spec.ExtraConfig = map[string]string{"admin.enabled": "true"} // override admin user through extraConfig + }) + + By("verifying that extraConfig setting overrides CR field") + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + Consistently(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + + By("simulating the user manually modifying the ConfigMap without doing so via the ArgoCD CR") + configmapFixture.Update(argocdConfigMap, func(cm *corev1.ConfigMap) { + cm.Data["admin.enabled"] = "false" + }) + + By("the user's simulated change should be reverted back to the desired state expressed within the ArgoCD CR") + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + Consistently(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true"), "operator should reject any manual updates to the configmap.") + + By("updating CR to use a connector, via .spec.sso.dex.config") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.DisableAdmin = true + ac.Spec.SSO = &argov1beta1api.ArgoCDSSOSpec{ + Provider: argov1beta1api.SSOProviderTypeDex, + Dex: &argov1beta1api.ArgoCDDexSpec{}, + } + ac.Spec.SSO.Dex.Config = `connectors: + - type: github + id: github + name: github-using-first-class + config: + clientID: first-class + clientSecret: $dex.github.clientSecret + orgs: + - name: first-class` + + }) + + By("verifying CR .spec.sso.dex.config is set in the ConfigMap") + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + Consistently(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("dex.config", `connectors: + - type: github + id: github + name: github-using-first-class + config: + clientID: first-class + clientSecret: $dex.github.clientSecret + orgs: + - name: first-class`)) + + By("overriding .spec.sso.dex.config via .spec.extraConfig with a different value") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + + ac.Spec.DisableAdmin = true + ac.Spec.SSO.Provider = argov1beta1api.SSOProviderTypeDex + ac.Spec.SSO.Dex.Config = `connectors: + - type: github + id: github + name: github-using-first-class + config: + clientID: first-class + clientSecret: $dex.github.clientSecret + orgs: + - name: first-class` + + ac.Spec.ExtraConfig = map[string]string{ + "admin.enabled": "true", + "dex.config": `connectors: + - type: github + id: github + name: github-using-extra-config + config: + clientID: extra-config + clientSecret: $dex.github.clientSecret + orgs: + - name: extra-config`, + } + }) + + By("verifying value specified in .spec.extraConfig overrides the value specified in spec field") + + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + Consistently(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("admin.enabled", "true")) + Eventually(argocdConfigMap).Should(configmapFixture.HaveStringDataKeyValue("dex.config", `connectors: + - type: github + id: github + name: github-using-extra-config + config: + clientID: extra-config + clientSecret: $dex.github.clientSecret + orgs: + - name: extra-config`)) + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-063_validate_dex_liveness_probe_test.go b/test/openshift/e2e/ginkgo/parallel/1-063_validate_dex_liveness_probe_test.go new file mode 100644 index 000000000..805d0a4eb --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-063_validate_dex_liveness_probe_test.go @@ -0,0 +1,121 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-063_validate_dex_liveness_probe_test", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies dex server Pod has expected liveness probe values", func() { + + By("verifying Argo CD is ready") + argoCD, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying dex server Pod has expected liveness probe values") + Eventually(func() bool { + + var podList corev1.PodList + if err := k8sClient.List(ctx, &podList, &client.ListOptions{Namespace: "openshift-gitops"}); err != nil { + GinkgoWriter.Println(err) + return false + } + + var pod corev1.Pod + for idx := range podList.Items { + currPod := podList.Items[idx] + if val, exists := currPod.Labels["app.kubernetes.io/name"]; exists && val == "openshift-gitops-dex-server" { + pod = currPod + break + } + } + + if len(pod.Spec.Containers) != 1 { + return false + } + + container := pod.Spec.Containers[0] + livenessProbe := container.LivenessProbe + if livenessProbe == nil { + return false + } + + if livenessProbe.FailureThreshold != int32(3) { + return false + } + + httpGet := livenessProbe.HTTPGet + if (*httpGet).Path != "/healthz/live" { + return false + } + + if (*httpGet).Port != intstr.FromInt(5558) { + return false + } + if (*httpGet).Scheme != corev1.URISchemeHTTP { + return false + } + if livenessProbe.InitialDelaySeconds != int32(60) { + return false + } + + if livenessProbe.PeriodSeconds != int32(30) { + return false + } + + if livenessProbe.SuccessThreshold != int32(1) { + return false + } + + if livenessProbe.TimeoutSeconds != int32(1) { + return false + } + + return true + + }).Should(BeTrue()) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-063_validate_statefulset_restart_test.go b/test/openshift/e2e/ginkgo/parallel/1-063_validate_statefulset_restart_test.go new file mode 100644 index 000000000..eb7f1d670 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-063_validate_statefulset_restart_test.go @@ -0,0 +1,82 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-063_validate_statefulset_restart", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that if a user modifies application controller image that it is reconciled back to desired image", func() { + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying Application Controller StatefulSet is available") + ssAppController := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-application-controller", Namespace: ns.Name}, + } + Eventually(ssAppController).Should(k8sFixture.ExistByName()) + Eventually(ssAppController, "2m", "5s").Should(statefulsetFixture.HaveReadyReplicas(1)) + + By("updating Application Controller to an invalid image, simulating a user trying to modify the resource manually") + statefulsetFixture.Update(ssAppController, func(ss *appsv1.StatefulSet) { + ss.Spec.Template.Spec.Containers[0].Image = "invalid_image" + }) + + By("verifying the Application Controller image is reverted by operator") + Eventually(ssAppController).Should(statefulsetFixture.NotHaveContainerImage("invalid_image", 0)) + Consistently(ssAppController).Should(statefulsetFixture.NotHaveContainerImage("invalid_image", 0)) + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-064_validate_security_contexts_test.go b/test/openshift/e2e/ginkgo/parallel/1-064_validate_security_contexts_test.go new file mode 100644 index 000000000..1becd699a --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-064_validate_security_contexts_test.go @@ -0,0 +1,197 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-064_validate_security_contexts", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that various Argo CD component workloads have expected security context", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + ApplicationSet: &argov1beta1api.ArgoCDApplicationSet{ + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("2"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("250m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + }, + }, + Notifications: argov1beta1api.ArgoCDNotifications{ + Enabled: true, + }, + SSO: &argov1beta1api.ArgoCDSSOSpec{ + Provider: argov1beta1api.SSOProviderTypeDex, + Dex: &argov1beta1api.ArgoCDDexSpec{ + OpenShiftOAuth: true, + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("250m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying that each Argo CD deployment has expected security context") + + deployments := []string{"argocd-applicationset-controller", "argocd-dex-server", "argocd-notifications-controller", "argocd-redis", "argocd-repo-server", "argocd-server"} + for _, deployment := range deployments { + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deployment, Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + + By("verifying " + depl.Name) + + containers := depl.Spec.Template.Spec.Containers + Expect(containers).To(HaveLen(1)) + + container := containers[0] + secContext := container.SecurityContext + Expect(secContext).ToNot(BeNil()) + + if depl.Name == "argocd-applicationset-controller" { + Expect(*secContext).To(Equal(corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}}, + AllowPrivilegeEscalation: ptr.To(false), + ReadOnlyRootFilesystem: ptr.To(true), + RunAsNonRoot: ptr.To(true), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + LocalhostProfile: nil, + }, + })) + } else if depl.Name == "argocd-dex-server" { + Expect(*secContext).To(Equal(corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}}, + AllowPrivilegeEscalation: ptr.To(false), + RunAsNonRoot: ptr.To(true), + ReadOnlyRootFilesystem: ptr.To(true), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + LocalhostProfile: nil, + }, + })) + } else if depl.Name == "argocd-notifications-controller" { + Expect(*secContext).To(Equal(corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}}, + AllowPrivilegeEscalation: ptr.To(false), + RunAsNonRoot: ptr.To(true), + ReadOnlyRootFilesystem: ptr.To(true), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + LocalhostProfile: nil, + }, + })) + + Expect(depl.Spec.Template.Spec.SecurityContext.RunAsNonRoot).To(Equal(ptr.To(true))) + + } else if depl.Name == "argocd-redis" { + Expect(*secContext).To(Equal(corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}}, + AllowPrivilegeEscalation: ptr.To(false), + RunAsNonRoot: ptr.To(true), + ReadOnlyRootFilesystem: ptr.To(true), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + LocalhostProfile: nil, + }, + })) + + } else if depl.Name == "argocd-repo-server" { + Expect(*secContext).To(Equal(corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}}, + AllowPrivilegeEscalation: ptr.To(false), + RunAsNonRoot: ptr.To(true), + ReadOnlyRootFilesystem: ptr.To(true), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + LocalhostProfile: nil, + }, + })) + + } else if depl.Name == "argocd-server" { + Expect(*secContext).To(Equal(corev1.SecurityContext{ + Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}}, + AllowPrivilegeEscalation: ptr.To(false), + RunAsNonRoot: ptr.To(true), + ReadOnlyRootFilesystem: ptr.To(true), + SeccompProfile: &corev1.SeccompProfile{ + Type: corev1.SeccompProfileTypeRuntimeDefault, + LocalhostProfile: nil, + }, + })) + + } else { + Fail("unrecognized deployment: " + depl.Name) + } + } + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-065_validate_redis_ha_anti_affinity_test.go b/test/openshift/e2e/ginkgo/parallel/1-065_validate_redis_ha_anti_affinity_test.go new file mode 100644 index 000000000..caeaec051 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-065_validate_redis_ha_anti_affinity_test.go @@ -0,0 +1,100 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + nodeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/node" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-065_validate_redis_ha_anti_affinity", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensuring that Redis HA StatefulSet has expected PodAffinity", func() { + + By("verifying we are running on a cluster with at least 3 nodes. This is required for Redis HA") + nodeFixture.ExpectHasAtLeastXNodes(3) + + // Note: Redis HA requires a cluster which contains multiple nodes + + By("creating simple namespace-scoped Argo CD instance with HA enabled") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + HA: argov1beta1api.ArgoCDHASpec{ + Enabled: true, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "5m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying redis HA server exists and has the appropriate anti-affinity") + redisHAStatefulSet := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-redis-ha-server", Namespace: ns.Name}, + } + Eventually(redisHAStatefulSet).Should(k8sFixture.ExistByName()) + + Expect(*redisHAStatefulSet.Spec.Template.Spec.Affinity).To(Equal(corev1.Affinity{ + PodAntiAffinity: &corev1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/name": "argocd-redis-ha", + }, + }, + TopologyKey: "kubernetes.io/hostname", + }, + }, + }, + })) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-066_validate_redis_secure_comm_no_autotls_no_ha_test.go b/test/openshift/e2e/ginkgo/parallel/1-066_validate_redis_secure_comm_no_autotls_no_ha_test.go new file mode 100644 index 000000000..0fabf1cb0 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-066_validate_redis_secure_comm_no_autotls_no_ha_test.go @@ -0,0 +1,162 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "os" + "time" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deplFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-066_validate_redis_secure_comm_no_autotls_no_ha", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that Argo CD components correctly inherit 'argocd-operator-redis-tls' Secret once it is created", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + expectComponentsAreRunning := func() { + + time.Sleep(15 * time.Second) // I don't see an easier way to detect when deployment/statefulset controller have reconciled the changes we have made. So instead we just use a long delay. + + deploymentsShouldExist := []string{"argocd-redis", "argocd-server", "argocd-repo-server"} + for _, depl := range deploymentsShouldExist { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: depl, Namespace: ns.Name}} + Eventually(depl, "60s", "5s").Should(k8sFixture.ExistByName()) + Eventually(depl, "60s", "5s").Should(deplFixture.HaveReplicas(1)) + Eventually(depl, "60s", "5s").Should(deplFixture.HaveReadyReplicas(1)) + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(statefulSet, "60s", "5s").Should(k8sFixture.ExistByName()) + Eventually(statefulSet, "60s", "5s").Should(statefulsetFixture.HaveReplicas(1)) + Eventually(statefulSet, "60s", "5s").Should(statefulsetFixture.HaveReadyReplicas(1)) + + } + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + expectComponentsAreRunning() + + By("generating a test certificate to use with redis, using openssl") + + redis_crt_File, err := os.CreateTemp("", "redis.crt") + Expect(err).To(BeNil()) + + redis_key_File, err := os.CreateTemp("", "redis.key") + Expect(err).To(BeNil()) + + openssl_test_File, err := os.CreateTemp("", "openssl_test.cnf") + Expect(err).To(BeNil()) + + opensslTestCNFContents := "\n[SAN]\nsubjectAltName=DNS:argocd-redis." + ns.Name + ".svc.cluster.local\n[req]\ndistinguished_name=req" + + err = os.WriteFile(openssl_test_File.Name(), ([]byte)(opensslTestCNFContents), 0666) + Expect(err).To(BeNil()) + + _, err = osFixture.ExecCommandWithOutputParam(false, "openssl", "req", "-new", "-x509", "-sha256", + "-subj", "/C=XX/ST=XX/O=Testing/CN=redis", + "-reqexts", "SAN", + "-extensions", "SAN", + "-config", openssl_test_File.Name(), + "-keyout", redis_key_File.Name(), + "-out", redis_crt_File.Name(), + "-newkey", "rsa:4096", + "-nodes", + "-days", "10", + ) + Expect(err).ToNot(HaveOccurred()) + + _, err = osFixture.ExecCommand("oc", "create", "secret", "tls", "argocd-operator-redis-tls", "--key="+redis_key_File.Name(), "--cert="+redis_crt_File.Name(), "-n", ns.Name) + Expect(err).ToNot(HaveOccurred()) + + expectComponentsAreRunning() + + _, err = osFixture.ExecCommand("oc", "annotate", "secret", "argocd-operator-redis-tls", "argocds.argoproj.io/name=argocd", "-n", ns.Name) + Expect(err).ToNot(HaveOccurred()) + + By("verifying that all the components restart successfully once we define the argocd-operator-redis-tls Secret") + expectComponentsAreRunning() + + redisDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-redis", Namespace: ns.Name}} + Eventually(redisDepl).Should(k8sFixture.ExistByName()) + + By("expecting redis-server to have desired container process command/arguments") + + Expect(redisDepl).To(deplFixture.HaveContainerCommandSubstring("redis-server --protected-mode no --save \"\" --appendonly no --requirepass "+"$(REDIS_PASSWORD)"+" --tls-port 6379 --port 0 --tls-cert-file /app/config/redis/tls/tls.crt --tls-key-file /app/config/redis/tls/tls.key --tls-auth-clients no", 0), + "TLS .spec.template.spec.containers.args for argocd-redis deployment are wrong") + + repoServerDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-repo-server", Namespace: ns.Name}} + Eventually(repoServerDepl).Should(k8sFixture.ExistByName()) + + By("expecting repo-server to have desired container process command/arguments") + Expect(repoServerDepl).To(deplFixture.HaveContainerCommandSubstring("uid_entrypoint.sh argocd-repo-server --redis argocd-redis."+ns.Name+".svc.cluster.local:6379 --redis-use-tls --redis-ca-certificate /app/config/reposerver/tls/redis/tls.crt --loglevel info --logformat text", 0), + "TLS .spec.template.spec.containers.command for argocd-repo-server deployment is wrong") + + argocdServerDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: ns.Name}} + Eventually(argocdServerDepl).Should(k8sFixture.ExistByName()) + + By("expecting argocd-server to have desired container process command/arguments") + Expect(argocdServerDepl).To(deplFixture.HaveContainerCommandSubstring("argocd-server --staticassets /shared/app --dex-server https://argocd-dex-server."+ns.Name+".svc.cluster.local:5556 --repo-server argocd-repo-server."+ns.Name+".svc.cluster.local:8081 --redis argocd-redis."+ns.Name+".svc.cluster.local:6379 --redis-use-tls --redis-ca-certificate /app/config/server/tls/redis/tls.crt --loglevel info --logformat text", 0), + "TLS .spec.template.spec.containers.command for argocd-server deployment is wrong") + + By("expecting application-controller to have desired container process command/arguments") + applicationControllerSS := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(applicationControllerSS).Should(k8sFixture.ExistByName()) + + Expect(applicationControllerSS).To(statefulsetFixture.HaveContainerCommandSubstring("argocd-application-controller --operation-processors 10 --redis argocd-redis."+ns.Name+".svc.cluster.local:6379 --redis-use-tls --redis-ca-certificate /app/config/controller/tls/redis/tls.crt --repo-server argocd-repo-server."+ns.Name+".svc.cluster.local:8081 --status-processors 20 --kubectl-parallelism-limit 10 --loglevel info --logformat text", 0), + "TLS .spec.template.spec.containers.command for argocd-application-controller statefulsets is wrong") + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-067_validate_redis_secure_comm_no_autotls_ha_test.go b/test/openshift/e2e/ginkgo/parallel/1-067_validate_redis_secure_comm_no_autotls_ha_test.go new file mode 100644 index 000000000..483dd5d2c --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-067_validate_redis_secure_comm_no_autotls_ha_test.go @@ -0,0 +1,206 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "os" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deplFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + nodeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/node" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-067_validate_redis_secure_comm_no_autotls_ha", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that redis HA can be enabled with tls with generated certificate", func() { + By("verifying we are running on a cluster with at least 3 nodes. This is required for Redis HA") + nodeFixture.ExpectHasAtLeastXNodes(3) + + // Note: Redis HA requires a cluster which contains multiple nodes + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + HA: argov1beta1api.ArgoCDHASpec{ + Enabled: true, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + expectComponentsAreRunning := func() { + + // In BeAvailable() we wait 15 seconds for ArgoCD CR to be reconciled, this SHOULD be enough time. + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "5m", "10s").Should(argocdFixture.BeAvailable()) + + deploymentsShouldExist := []string{"argocd-redis-ha-haproxy", "argocd-server", "argocd-repo-server"} + for _, depl := range deploymentsShouldExist { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: depl, Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deplFixture.HaveReplicas(1)) + Eventually(depl).Should(deplFixture.HaveReadyReplicas(1)) + } + + statefulsetsShouldExist := []string{"argocd-redis-ha-server", "argocd-application-controller"} + for _, ss := range statefulsetsShouldExist { + + replicas := 1 + if ss == "argocd-redis-ha-server" { + replicas = 3 + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: ss, Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(statefulSet).Should(statefulsetFixture.HaveReplicas(replicas)) + Eventually(statefulSet).Should(statefulsetFixture.HaveReadyReplicas(replicas)) + } + + } + + expectComponentsAreRunning() + + By("generating a test certificate to use with redis, using openssl") + + redis_crt_File, err := os.CreateTemp("", "redis.crt") + Expect(err).To(BeNil()) + + redis_key_File, err := os.CreateTemp("", "redis.key") + Expect(err).To(BeNil()) + + openssl_test_File, err := os.CreateTemp("", "openssl_test.cnf") + Expect(err).To(BeNil()) + + opensslTestCNFContents := "\n[SAN]\nsubjectAltName=DNS:argocd-redis." + ns.Name + ".svc.cluster.local\n[req]\ndistinguished_name=req" + + err = os.WriteFile(openssl_test_File.Name(), ([]byte)(opensslTestCNFContents), 0666) + Expect(err).To(BeNil()) + + _, err = osFixture.ExecCommandWithOutputParam(false, "openssl", "req", "-new", "-x509", "-sha256", + "-subj", "/C=XX/ST=XX/O=Testing/CN=redis", + "-reqexts", "SAN", + "-extensions", "SAN", + "-config", openssl_test_File.Name(), + "-keyout", redis_key_File.Name(), + "-out", redis_crt_File.Name(), + "-newkey", "rsa:4096", + "-nodes", + "-days", "10", + ) + Expect(err).ToNot(HaveOccurred()) + + By("creating argocd-operator-redis-tls secret from that cert") + + _, err = osFixture.ExecCommand("oc", "create", "secret", "tls", "argocd-operator-redis-tls", "--key="+redis_key_File.Name(), "--cert="+redis_crt_File.Name(), "-n", ns.Name) + Expect(err).ToNot(HaveOccurred()) + + expectComponentsAreRunning() + + By("adding argo cd label to argocd-operator-redis-tls secret") + _, err = osFixture.ExecCommand("oc", "annotate", "secret", "argocd-operator-redis-tls", "argocds.argoproj.io/name=argocd", "-n", ns.Name) + Expect(err).ToNot(HaveOccurred()) + + expectComponentsAreRunning() + + By("extracting the contents of /data/conf/redis.conf and checking it contains expected values") + redisConf, err := osFixture.ExecCommandWithOutputParam(false, "oc", "exec", "-i", "pod/argocd-redis-ha-server-0", "-n", ns.Name, "-c", "redis", "--", "cat", "/data/conf/redis.conf") + Expect(err).ToNot(HaveOccurred()) + expectedRedisConfig := []string{ + "port 0", + "tls-port 6379", + "tls-cert-file /app/config/redis/tls/tls.crt", + "tls-ca-cert-file /app/config/redis/tls/tls.crt", + "tls-key-file /app/config/redis/tls/tls.key", + "tls-replication yes", + "tls-auth-clients no", + } + for _, line := range expectedRedisConfig { + Expect(redisConf).To(ContainSubstring(line)) + } + + By("extracting the contents of /data/conf/sentinel.conf and checking it contains expected values") + sentinelConf, err := osFixture.ExecCommandWithOutputParam(false, "oc", "exec", "-i", "pod/argocd-redis-ha-server-0", "-n", ns.Name, "-c", "redis", "--", "cat", "/data/conf/sentinel.conf") + Expect(err).ToNot(HaveOccurred()) + expectedSentinelConfig := []string{ + "port 0", + "tls-port 26379", + "tls-cert-file \"/app/config/redis/tls/tls.crt\"", + "tls-ca-cert-file \"/app/config/redis/tls/tls.crt\"", + "tls-key-file \"/app/config/redis/tls/tls.key\"", + "tls-replication yes", + "tls-auth-clients no", + } + for _, line := range expectedSentinelConfig { + Expect(sentinelConf).To(ContainSubstring(line)) + } + + repoServerDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-repo-server", Namespace: ns.Name}} + Eventually(repoServerDepl).Should(k8sFixture.ExistByName()) + + By("expecting repo-server to have desired container process command/arguments") + Expect(repoServerDepl).To(deplFixture.HaveContainerCommandSubstring("uid_entrypoint.sh argocd-repo-server --redis argocd-redis-ha-haproxy."+ns.Name+".svc.cluster.local:6379 --redis-use-tls --redis-ca-certificate /app/config/reposerver/tls/redis/tls.crt --loglevel info --logformat text", 0), + "TLS .spec.template.spec.containers.command for argocd-repo-server deployment is wrong") + + argocdServerDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: ns.Name}} + Eventually(argocdServerDepl).Should(k8sFixture.ExistByName()) + + By("expecting argocd-server to have desired container process command/arguments") + Expect(argocdServerDepl).To(deplFixture.HaveContainerCommandSubstring("argocd-server --staticassets /shared/app --dex-server https://argocd-dex-server."+ns.Name+".svc.cluster.local:5556 --repo-server argocd-repo-server."+ns.Name+".svc.cluster.local:8081 --redis argocd-redis-ha-haproxy."+ns.Name+".svc.cluster.local:6379 --redis-use-tls --redis-ca-certificate /app/config/server/tls/redis/tls.crt --loglevel info --logformat text", 0), + "TLS .spec.template.spec.containers.command for argocd-server deployment is wrong") + + By("expecting application-controller to have desired container process command/arguments") + applicationControllerSS := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(applicationControllerSS).Should(k8sFixture.ExistByName()) + + Expect(applicationControllerSS).To(statefulsetFixture.HaveContainerCommandSubstring("argocd-application-controller --operation-processors 10 --redis argocd-redis-ha-haproxy."+ns.Name+".svc.cluster.local:6379 --redis-use-tls --redis-ca-certificate /app/config/controller/tls/redis/tls.crt --repo-server argocd-repo-server."+ns.Name+".svc.cluster.local:8081 --status-processors 20 --kubectl-parallelism-limit 10 --loglevel info --logformat text", 0), + "TLS .spec.template.spec.containers.command for argocd-application-controller statefulsets is wrong") + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-069_validate_redis_secure_comm_autotls_ha_test.go b/test/openshift/e2e/ginkgo/parallel/1-069_validate_redis_secure_comm_autotls_ha_test.go new file mode 100644 index 000000000..3bbd01d52 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-069_validate_redis_secure_comm_autotls_ha_test.go @@ -0,0 +1,126 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deplFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + nodeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/node" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-069_validate_redis_secure_comm_autotls_ha", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifying when HA is enabled that Argo CD starts successfully in HA mode, and that AutoTLS can be enabled", func() { + + By("verifying we are running on a cluster with at least 3 nodes. This is required for Redis HA") + nodeFixture.ExpectHasAtLeastXNodes(3) + + // Note: Redis HA requires a cluster which contains multiple nodes + + By("creating simple namespace-scoped Argo CD instance with HA enabled") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + HA: argov1beta1api.ArgoCDHASpec{ + Enabled: true, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + expectComponentsAreRunning := func() { + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + deploymentsShouldExist := []string{"argocd-redis-ha-haproxy", "argocd-server", "argocd-repo-server"} + for _, depl := range deploymentsShouldExist { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: depl, Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deplFixture.HaveReplicas(1)) + Eventually(depl).Should(deplFixture.HaveReadyReplicas(1)) + } + + statefulsetsShouldExist := []string{"argocd-redis-ha-server", "argocd-application-controller"} + for _, ss := range statefulsetsShouldExist { + + replicas := 1 + if ss == "argocd-redis-ha-server" { + replicas = 3 + } + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: ss, Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(statefulSet).Should(statefulsetFixture.HaveReplicas(replicas)) + Eventually(statefulSet).Should(statefulsetFixture.HaveReadyReplicas(replicas)) + } + + } + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + expectComponentsAreRunning() + + By("enabling redis HA autoTLS for openshift") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Redis.AutoTLS = "openshift" + }) + + expectComponentsAreRunning() + + By("verifying Redis TLS Secret exists and has data") + redisTLSSecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "argocd-operator-redis-tls", Namespace: ns.Name}} + Eventually(redisTLSSecret).Should(k8sFixture.ExistByName()) + + Expect(string(redisTLSSecret.Type)).To(Equal("kubernetes.io/tls")) + Expect(redisTLSSecret.Data).To(HaveLen(2)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-070_validate_config_management_plugin_test.go b/test/openshift/e2e/ginkgo/parallel/1-070_validate_config_management_plugin_test.go new file mode 100644 index 000000000..76d2ce4b5 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-070_validate_config_management_plugin_test.go @@ -0,0 +1,148 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + appv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + applicationFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-070_validate_config_management_plugin_test", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that an Argo CD Application with a ConfigManagementPlugin mounted via sidecar will deploy as expected", func() { + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + By("creating simple namespace-scoped Argo CD instance with a CMP sidecar, where the sidecar is a simple bash script") + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + Repo: argov1beta1api.ArgoCDRepoSpec{ + SidecarContainers: []corev1.Container{{ + Name: "cmp", + Command: []string{"/var/run/argocd/argocd-cmp-server"}, // Entrypoint should be Argo CD lightweight CMP server ie. argocd-cmp-server + Image: "quay.io/fedora/fedora:latest", // This can be off-the-shelf or custom-built image + SecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: ptr.To(true), + }, + VolumeMounts: []corev1.VolumeMount{ + {MountPath: "/var/run/argocd", Name: "var-files"}, + {MountPath: "/home/argocd/cmp-server/plugins", Name: "plugins"}, + {MountPath: "/tmp", Name: "tmp"}, + // Remove this volumeMount if you've chosen to bake the config file into the sidecar image. + {MountPath: "/home/argocd/cmp-server/config/plugin.yaml", Name: "cmp-plugin", SubPath: "plugin.yaml"}, + }, + }}, + Volumes: []corev1.Volume{{Name: "cmp-plugin", VolumeSource: corev1.VolumeSource{ConfigMap: &corev1.ConfigMapVolumeSource{LocalObjectReference: corev1.LocalObjectReference{Name: "cmp-plugin"}}}}}, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("creating ConfigMap with CMP plugin that will echo a ConfigMap that does not exist in source repository") + cmpPluginCM := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: "cmp-plugin", Namespace: ns.Name}, + Data: map[string]string{"plugin.yaml": `apiVersion: v1 +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-plugin +spec: + version: v1.0 + generate: + command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$FOO\", \"Bar\": \"baz\"}}}"'] + discover: + find: + command: [sh, -c, 'echo "FOUND"; exit 0'] + allowConcurrency: true + lockRepo: true`}, + } + + Expect(k8sClient.Create(ctx, cmpPluginCM)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("creating an Argo CD Application which will deploy guestbook example using CMP plugin") + app := &appv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook", + Namespace: ns.Name, + }, + Spec: appv1alpha1.ApplicationSpec{ + Project: "default", + Source: &appv1alpha1.ApplicationSource{ + RepoURL: "https://github.com/redhat-developer/gitops-operator", + Path: "test/examples/guestbook", + TargetRevision: "HEAD", + Plugin: &appv1alpha1.ApplicationSourcePlugin{ + Env: appv1alpha1.Env{{Name: "FOO", Value: "myfoo"}}, + }, + }, + Destination: appv1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: ns.Name, + }, + SyncPolicy: &appv1alpha1.SyncPolicy{Automated: &appv1alpha1.SyncPolicyAutomated{}}, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("verifying deploying the Application succeeded") + Eventually(app, "4m", "5s").Should(applicationFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app, "4m", "5s").Should(applicationFixture.HaveSyncStatusCode(appv1alpha1.SyncStatusCodeSynced)) + + By("verifying that the ConfigMap generated by the CMP plugin was successfully deployed to teh target namespace") + guestbookCM := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "guestbook", Namespace: ns.Name}} + Eventually(guestbookCM).Should(k8sFixture.ExistByName()) + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-071_validate_SCC_HA_test.go b/test/openshift/e2e/ginkgo/parallel/1-071_validate_SCC_HA_test.go new file mode 100644 index 000000000..666135187 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-071_validate_SCC_HA_test.go @@ -0,0 +1,193 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + securityv1 "github.com/openshift/api/security/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + nodeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/node" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/pod" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-071_validate_SCC_HA", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("creates SCC and ensure HA Argo CD starts as expected", func() { + + By("verifying we are running on a cluster with at least 3 nodes. This is required for Redis HA") + nodeFixture.ExpectHasAtLeastXNodes(3) + + scc := &securityv1.SecurityContextConstraints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restricted-dropcaps", + }, + } + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(scc), scc); err == nil { + Expect(k8sClient.Delete(ctx, scc)).To(Succeed()) + } else { + Expect(err).ToNot(BeNil()) + } + + scc = &securityv1.SecurityContextConstraints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "restricted-dropcaps", + }, + AllowHostDirVolumePlugin: false, + AllowHostIPC: false, + AllowHostNetwork: false, + AllowHostPID: false, + AllowHostPorts: false, + AllowPrivilegeEscalation: ptr.To(false), + AllowPrivilegedContainer: false, + AllowedCapabilities: nil, + DefaultAddCapabilities: nil, + FSGroup: securityv1.FSGroupStrategyOptions{ + Type: securityv1.FSGroupStrategyMustRunAs, + }, + Groups: []string{"system:authenticated"}, + Priority: nil, + ReadOnlyRootFilesystem: false, + RequiredDropCapabilities: []corev1.Capability{ + "KILL", + "MKNOD", + "SETUID", + "SETGID", + "CHOWN", + "DAC_OVERRIDE", + "FOWNER", + "FSETID", + "SETPCAP", + "NET_BIND_SERVICE", + }, + RunAsUser: securityv1.RunAsUserStrategyOptions{ + Type: securityv1.RunAsUserStrategyMustRunAsRange, + }, + SELinuxContext: securityv1.SELinuxContextStrategyOptions{ + Type: securityv1.SELinuxStrategyMustRunAs, + }, + SupplementalGroups: securityv1.SupplementalGroupsStrategyOptions{ + Type: securityv1.SupplementalGroupsStrategyRunAsAny, + }, + Users: []string{}, + Volumes: []securityv1.FSType{ + "configMap", + "downwardAPI", + "emptyDir", + "persistentVolumeClaim", + "projected", + "secret", + }, + } + Expect(k8sClient.Create(ctx, scc)).To(Succeed()) + + defer func() { + Expect(k8sClient.Delete(ctx, scc)).To(Succeed()) + }() + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + By("creating simple namespace-scoped Argo CD instance") + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + expectPodsLabelsAreFoundAndRunningByPodLabel := func(expectedPodLabels []string) { + + By("verifying workload pods exist and are running") + var pods corev1.PodList + Expect(k8sClient.List(ctx, &pods, &client.ListOptions{Namespace: ns.Name})).To(Succeed()) + + for _, expectedPodLabel := range expectedPodLabels { + match := false + for _, pod := range pods.Items { + if pod.Labels != nil && pod.Labels["app.kubernetes.io/name"] == expectedPodLabel { + match = true + Expect(pod.Status.Phase).To(Equal(corev1.PodRunning)) + break + } + } + Expect(match).To(BeTrue(), "unable to locate Pod with label 'app.kubernetes.io/name' of "+expectedPodLabel) + } + + } + + expectedPodLabels := []string{"argocd-application-controller", "argocd-redis", "argocd-repo-server", "argocd-server"} + expectPodsLabelsAreFoundAndRunningByPodLabel(expectedPodLabels) + + By("enabling HA on Argo CD") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.HA.Enabled = true + }) + + By("waiting for HA to be enabled on Argo CD, and Argo CD to be ready") + Eventually(argoCD, "5m", "10s").Should(argocdFixture.BeAvailable()) // enabling HA takes a while + + expectedPodLabels = []string{"argocd-application-controller", "argocd-redis-ha-haproxy", "argocd-repo-server", "argocd-server"} + expectPodsLabelsAreFoundAndRunningByPodLabel(expectedPodLabels) + + By("verifying workload HA pods exist and are running") + var pods corev1.PodList + Expect(k8sClient.List(ctx, &pods, &client.ListOptions{Namespace: ns.Name})).To(Succeed()) + + redisServer1Pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "argocd-redis-ha-server-1", Namespace: ns.Name}} + Eventually(redisServer1Pod, "3m", "1s").Should(k8sFixture.ExistByName()) + Eventually(redisServer1Pod, "3m", "1s").Should(pod.HavePhase(corev1.PodRunning)) + + redisServer2Pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "argocd-redis-ha-server-2", Namespace: ns.Name}} + Eventually(redisServer2Pod, "3m", "1s").Should(k8sFixture.ExistByName()) + Eventually(redisServer2Pod, "3m", "1s").Should(pod.HavePhase(corev1.PodRunning)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-072_validate_liveness_probe_removed_test.go b/test/openshift/e2e/ginkgo/parallel/1-072_validate_liveness_probe_removed_test.go new file mode 100644 index 000000000..071bbbff4 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-072_validate_liveness_probe_removed_test.go @@ -0,0 +1,76 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-072_validate_liveness_probe_removed", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that livenessProbe is not set on argocd-application-controller StatefulSet on default namespace-scoped Argo CD instance", func() { + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + By("creating simple namespace-scoped Argo CD instance") + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying that StatefulSet does not have livenessProbe") + + ss := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns.Name}} + Eventually(ss).Should(k8sFixture.ExistByName()) + + for _, container := range ss.Spec.Template.Spec.Containers { + Expect(container.LivenessProbe).To(BeNil(), "livenessProbe should not exist on statefulset.apps/argocd-application-controller") + } + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-073_validate_rhsso_test.go b/test/openshift/e2e/ginkgo/parallel/1-073_validate_rhsso_test.go new file mode 100644 index 000000000..dc4de5e51 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-073_validate_rhsso_test.go @@ -0,0 +1,251 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "encoding/json" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + openshiftappsv1 "github.com/openshift/api/apps/v1" + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + deploymentconfigFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deploymentconfig" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-073_validate_rhsso_test", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that the keycloak installed by operator has all the expected resources and is configured as expected, in Argo CD config and in Keycloak config", func() { + + if fixture.EnvLocalRun() { + Skip("This test is known not to work when running gitops operator locally, in both kuttl and ginkgo forms") + return + } + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + By("creating simple namespace-scoped Argo CD instance where keycloak is enabled with a fake root cert") + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-keycloak", Namespace: ns.Name, + Labels: map[string]string{"example": "keycloak"}}, + Spec: argov1beta1api.ArgoCDSpec{ + SSO: &argov1beta1api.ArgoCDSSOSpec{ + Provider: argov1beta1api.SSOProviderTypeKeycloak, + Keycloak: &argov1beta1api.ArgoCDKeycloakSpec{ + RootCA: "---BEGIN---END---", + }, + }, + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying DeploymentConfig created by operator has expected values") + + dc := &openshiftappsv1.DeploymentConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "keycloak", Namespace: ns.Name}, + } + Eventually(dc).Should(k8sFixture.ExistByName()) + + Expect(dc.Spec.Selector).To(Equal(map[string]string{ + "deploymentConfig": "keycloak", + })) + + Expect(dc.Spec.Strategy).To(Equal(openshiftappsv1.DeploymentStrategy{ + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("250m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + }, + RecreateParams: &openshiftappsv1.RecreateDeploymentStrategyParams{TimeoutSeconds: ptr.To(int64(600))}, + Type: openshiftappsv1.DeploymentStrategyTypeRecreate, + ActiveDeadlineSeconds: ptr.To(int64(21600)), + })) + + Expect(dc.Spec.Template.ObjectMeta).Should(Equal(metav1.ObjectMeta{ + Labels: map[string]string{ + "application": "keycloak", + "deploymentConfig": "keycloak", + }, + Name: "keycloak", + })) + + Expect(dc.Spec.Template.Spec.Containers[0].Resources).Should(Equal(corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("1"), + corev1.ResourceMemory: resource.MustParse("1Gi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, + })) + + Expect(dc.Spec.Template.Spec.Containers[0].VolumeMounts).Should(Equal([]corev1.VolumeMount{ + {Name: "sso-x509-https-volume", MountPath: "/etc/x509/https", ReadOnly: true}, + {Name: "service-ca", MountPath: "/var/run/configmaps/service-ca", ReadOnly: true}, + {Name: "sso-probe-netrc-volume", MountPath: "/mnt/rh-sso"}, + })) + + Expect(dc.Spec.Template.Spec.RestartPolicy).Should(Equal(corev1.RestartPolicyAlways)) + + Expect(dc.Spec.Template.Spec.Volumes).Should(Equal([]corev1.Volume{ + { + Name: "sso-x509-https-volume", VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + DefaultMode: ptr.To(int32(420)), + SecretName: "sso-x509-https-secret", + }, + }, + }, + { + Name: "service-ca", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{ + Name: "keycloak-service-ca", + }, + }, + }, + }, + { + Name: "sso-probe-netrc-volume", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + Medium: corev1.StorageMediumMemory, + }, + }, + }, + })) + + Expect(dc.Spec.Triggers).To(Equal(openshiftappsv1.DeploymentTriggerPolicies{{Type: "ConfigChange"}})) + Eventually(dc, "6m", "5s").Should(deploymentconfigFixture.HaveReadyReplicas(1)) + + By("verifying Service, Route, and Secret exist and/or contain the expected values") + + keycloakService := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "keycloak", Namespace: ns.Name}} + Eventually(keycloakService).Should(k8sFixture.ExistByName()) + + keycloakRoute := &routev1.Route{ObjectMeta: metav1.ObjectMeta{Name: "keycloak", Namespace: ns.Name}} + Eventually(keycloakRoute).Should(k8sFixture.ExistByName()) + Expect(keycloakRoute.Spec.TLS.Termination).Should(Equal(routev1.TLSTerminationReencrypt)) + Expect(keycloakRoute.Spec.To).Should(Equal(routev1.RouteTargetReference{ + Kind: "Service", + Name: "keycloak", + Weight: ptr.To(int32(100)), + })) + Expect(keycloakRoute.Spec.WildcardPolicy).Should(Equal(routev1.WildcardPolicyNone)) + + keycloakSecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "keycloak-secret", Namespace: ns.Name}} + Eventually(keycloakSecret).Should(k8sFixture.ExistByName()) + Expect(keycloakSecret.Type).Should(Equal(corev1.SecretTypeOpaque)) + + By("wait for argocd-cm ConfigMap to be configured for keycloak") + argocdCM := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns.Name}} + Expect(argocdCM).Should(k8sFixture.ExistByName()) + + Eventually(argocdCM, "2m", "5s").Should(configmapFixture.HaveNonEmptyDataKey("oidc.config")) + + oidcConfigContents := argocdCM.Data["oidc.config"] + + findLineInOutput := func(key string, output string) string { + // input format: "clientid: argocd\n\n" + // output format, for 'clientid': "argocd" + + for _, line := range strings.Split(output, "\n") { + if strings.Contains(line, key) { + return strings.TrimSpace(line[strings.Index(line, ":")+1:]) + } + } + return "" + } + + By("verifying that oidc.config value of argocd-cm ConfigMap contains expected configuration values") + keycloakRouteHost := keycloakRoute.Spec.Host + Expect(findLineInOutput("issuer", oidcConfigContents)).Should(Equal("https://"+keycloakRouteHost+"/auth/realms/argocd"), "certificate issuer should be /auth/realms/argocd from the route host") + + Expect(findLineInOutput("clientid", oidcConfigContents)).Should(Equal("argocd")) + Expect(findLineInOutput("name", oidcConfigContents)).Should(Equal("Keycloak")) + Expect(findLineInOutput("rootca", oidcConfigContents)).Should(Equal("'---BEGIN---END---'")) + + By("extracting the access token for keycloak, to allow us to issue API commands") + output, err := osFixture.ExecCommandWithOutputParam(false, "curl", "-d", "client_id=admin-cli", "-d", "username="+string(keycloakSecret.Data["SSO_USERNAME"]), "-d", "password="+string(keycloakSecret.Data["SSO_PASSWORD"]), "-d", "grant_type=password", "https://"+keycloakRouteHost+"/auth/realms/master/protocol/openid-connect/token", "-k") + Expect(err).ToNot(HaveOccurred()) + + // Extract the JSON part of the output + output = output[strings.Index(output, "{\"access_token\""):] + + var jsonData map[string]any + Expect(json.Unmarshal([]byte(output), &jsonData)).ToNot(HaveOccurred()) + + accessToken := jsonData["access_token"].(string) + + By("executing the CURL command to verify the realm and client creation") + + output, err = osFixture.ExecCommandWithOutputParam(false, "curl", "-H", "Content-Type: application/json", "-H", "Authorization: bearer "+accessToken, "https://"+keycloakRouteHost+"/auth/admin/realms/argocd/clients", "-k") + Expect(err).ToNot(HaveOccurred()) + Expect(output).To(ContainSubstring("\"clientId\":\"argocd\"")) + + By("executing the CURL command to verify OpenShift-v4 IdP creation") + + output, err = osFixture.ExecCommandWithOutputParam(false, "curl", "-H", "Content-Type: application/json", "-H", "Authorization: bearer "+accessToken, "https://"+keycloakRouteHost+"/auth/admin/realms/argocd/identity-provider/instances", "-k") + Expect(err).ToNot(HaveOccurred()) + Expect(output).To(ContainSubstring("openshift-v4")) + Expect(output).To(ContainSubstring("\"syncMode\":\"FORCE\"")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-074_validate_terminating_namespace_block_test.go b/test/openshift/e2e/ginkgo/parallel/1-074_validate_terminating_namespace_block_test.go new file mode 100644 index 000000000..0c163b301 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-074_validate_terminating_namespace_block_test.go @@ -0,0 +1,142 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-074_validate_terminating_namespace_block", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that if one managed namespace is stuck in deleting state -- due to a finalizer -- it does not block other managed namespaces from being reconciled", func() { + + By("creating an Argo CD instance that will manage other namespaces") + gitops_2242_ns_main, cleanupFunc := fixture.CreateNamespaceWithCleanupFunc("gitops-2242-ns-main") + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gitops-2242-argocd", + Namespace: gitops_2242_ns_main.Name, + Finalizers: []string{"argoproj.io/finalizer"}, + }, + Spec: argov1beta1api.ArgoCDSpec{ + RBAC: argov1beta1api.ArgoCDRBACSpec{ + Policy: ptr.To("g, system:authenticated, role:admin"), + Scopes: ptr.To("[groups]"), + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + // This RoleBinding (ported from kuttl test) appears not to have a point: it grants openshift-gitops argo cd instance to this argo cd. + // I've left it commented out. + // + // nsRoleBinding := &rbacv1.RoleBinding{ + // ObjectMeta: metav1.ObjectMeta{ + // Name: "grant-argocd", + // Namespace: gitops_2242_ns_main.Name, + // }, + // RoleRef: rbacv1.RoleRef{ + // APIGroup: "rbac.authorization.k8s.io", + // Kind: "ClusterRole", + // Name: "admin", + // }, + // Subjects: []rbacv1.Subject{ + // {Kind: "ServiceAccount", Name: "openshift-gitops-argocd-application-controller", Namespace: "openshift-gitops"}}, + // } + // Expect(k8sClient.Create(ctx, nsRoleBinding)).To(Succeed()) + + gitops_2242_ns_first, cleanupFunc := fixture.CreateManagedNamespaceWithCleanupFunc("gitops-2242-ns-first", gitops_2242_ns_main.Name) + defer cleanupFunc() + + By("creating a ConfigMap with a finalizer, so that when the Namespace is deleted, the Namespace cannot finish deleting until the ConfigMap finalizer is removed") + firstConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-config-map-2", + Namespace: gitops_2242_ns_first.Name, + Finalizers: []string{ + "some.random/finalizer", + }, + }, + Data: map[string]string{ + "foo": "bar", + }, + } + Expect(k8sClient.Create(ctx, firstConfigMap)).To(Succeed()) + defer func() { + // At the end of the test, remove the finalizer from the ConfigMap so the NS can be deleted. + configmapFixture.Update(firstConfigMap, func(cm *corev1.ConfigMap) { + cm.ObjectMeta.Finalizers = nil + }) + }() + + By("starting to delete the Namespace in the background. This puts the Namespace into deletion state, but it cannot finish deletion until the ConfigMap has its finalizer removed, which happens at the end of the test") + go func() { + defer GinkgoRecover() + Expect(k8sClient.Delete(ctx, &gitops_2242_ns_first)).To(Succeed()) + }() + + By("creating a second managed namespace, to managed by the Argo CD instance") + gitops_2242_ns_second, cleanupFunc := fixture.CreateManagedNamespaceWithCleanupFunc("gitops-2242-ns-second", "gitops-2242-ns-main") + defer cleanupFunc() + + By("verifying that the operator is successfully able to grant access from the Argo CD instance to the second Namespace. That confirms that, even though the first namespace is in deletion state, that the operator is not blocked on other Namespaces") + argocdServerRoleBindingInGitops_2242_ns_second := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "gitops-2242-argocd-argocd-server", Namespace: gitops_2242_ns_second.Name}, + } + Eventually(argocdServerRoleBindingInGitops_2242_ns_second).Should(k8sFixture.ExistByName()) + + argocdApplicationServerRoleBindingInGitops_2242_ns_second := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "gitops-2242-argocd-argocd-application-controller", Namespace: gitops_2242_ns_second.Name}, + } + Eventually(argocdApplicationServerRoleBindingInGitops_2242_ns_second).Should(k8sFixture.ExistByName()) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-075_validate_dex_anyuid_test.go b/test/openshift/e2e/ginkgo/parallel/1-075_validate_dex_anyuid_test.go new file mode 100644 index 000000000..548382898 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-075_validate_dex_anyuid_test.go @@ -0,0 +1,109 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-075_validate_dex_anyuid", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that dex runs when serviceaccount has anyuid SCC", func() { + + By("creating an Argo CD instance with Dex OpenShift Auth enabled") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd", + Namespace: ns.Name, + }, + Spec: argov1beta1api.ArgoCDSpec{ + SSO: &argov1beta1api.ArgoCDSSOSpec{ + Provider: argov1beta1api.SSOProviderTypeDex, + Dex: &argov1beta1api.ArgoCDDexSpec{ + OpenShiftOAuth: true, + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("128Mi"), + corev1.ResourceCPU: resource.MustParse("250m"), + }, + Limits: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("256Mi"), + corev1.ResourceCPU: resource.MustParse("500m"), + }, + }, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying argocd-dex-server Deployment is working as expected") + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-dex-server", Namespace: ns.Name}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deploymentFixture.HaveReplicas(1)) + Eventually(depl).Should(deploymentFixture.HaveReadyReplicas(1)) + + By("adding SCC anyuid to the ServiceAccount used by dex-server") + _, err := osFixture.ExecCommand("oc", "adm", "policy", "add-scc-to-user", "anyuid", "-z", "argocd-argocd-dex-server", "-n", ns.Name) + Expect(err).ToNot(HaveOccurred()) + + By("force a restart of argocd-dex-server Deployment") + _, err = osFixture.ExecCommand("oc", "rollout", "restart", "deployment/argocd-dex-server", "-n", ns.Name) + Expect(err).ToNot(HaveOccurred()) + + By("verifying that argocd-dex-server is still working as expected") + Eventually(depl).Should(deploymentFixture.HaveReplicas(1)) + Eventually(depl).Should(deploymentFixture.HaveReadyReplicas(1)) + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-077_validate_disable_dex_removed_test.go b/test/openshift/e2e/ginkgo/parallel/1-077_validate_disable_dex_removed_test.go new file mode 100644 index 000000000..238d03915 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-077_validate_disable_dex_removed_test.go @@ -0,0 +1,95 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "encoding/json" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-077_validate_disable_dex_removed", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that DISABLE_DEX is not specified in the Subscription/CSV that was used to install the operator", func() { + + if fixture.EnvNonOLM() || fixture.EnvLocalRun() { + Skip("this test requires operator to have been installed via OLM") + return + } + + var operatorNameVersion string + + By("getting the Subscription and CSV that was used to install the operator") + + if fixture.EnvCI() { + subscription, err := fixture.GetSubscriptionInEnvCIEnvironment(k8sClient) + Expect(err).ToNot(HaveOccurred()) + Expect(subscription).ToNot(BeNil()) + + operatorNameVersion = subscription.Status.InstalledCSV + + } else { + subscription := &olmv1alpha1.Subscription{ + ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-operator", Namespace: "openshift-gitops-operator"}, + } + Expect(subscription).Should(k8sFixture.ExistByName()) + + operatorNameVersion = subscription.Status.InstalledCSV + + } + + Expect(operatorNameVersion).ShouldNot(BeEmpty()) + + By("verifying that the CSV install spec does not contain DISABLE_DEX") + + csv := &olmv1alpha1.ClusterServiceVersion{ObjectMeta: metav1.ObjectMeta{ + Name: operatorNameVersion, + Namespace: "openshift-gitops-operator", + }} + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(csv), csv)).To(Succeed()) + + deploymentSpecs := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs + outBytes, err := json.Marshal(deploymentSpecs) + Expect(err).ToNot(HaveOccurred()) + Expect(string(outBytes)).ToNot(ContainSubstring("DISABLE_DEX"), "DISABLE_DEX should not be present in the operator CSV.") + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-079_validate_vars_for_notificaitons_test.go b/test/openshift/e2e/ginkgo/parallel/1-079_validate_vars_for_notificaitons_test.go new file mode 100644 index 000000000..0ce68543e --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-079_validate_vars_for_notificaitons_test.go @@ -0,0 +1,102 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-079_validate_vars_for_notificaitons", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that setting an environment variable on notifications controller via ArgoCD CR will cause the env var to be set on notification controller Deployment", func() { + By("creating an Argo CD instance with notification enabled") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example-argocd", + Namespace: ns.Name, + }, + Spec: argov1beta1api.ArgoCDSpec{ + Notifications: argov1beta1api.ArgoCDNotifications{ + Enabled: true, + }, + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCD, "3m", "5s").Should(argocdFixture.HaveNotificationControllerStatus("Running")) + + By("waiting for notification controller to be ready") + notificationsController := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-notifications-controller", Namespace: ns.Name}} + Eventually(notificationsController).Should(k8sFixture.ExistByName()) + Eventually(notificationsController).Should(deploymentFixture.HaveReadyReplicas(1)) + + By("adding environment variable to Notifications controller via ArgoCD CR") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Notifications.Enabled = true + ac.Spec.Notifications.Env = []corev1.EnvVar{{Name: "foo", Value: "bar"}} + }) + + By("verifying env var is set on the notification controller Deployment, and the Deployment becomes ready") + Eventually(notificationsController).Should(deploymentFixture.HaveContainerWithEnvVar("foo", "bar", 0)) + Eventually(notificationsController).Should(deploymentFixture.HaveReadyReplicas(1)) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCD, "3m", "5s").Should(argocdFixture.HaveNotificationControllerStatus("Running")) + Eventually(argoCD, "3m", "5s").Should(argocdFixture.HaveServerStatus("Running")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-080_validate_regex_support_argocd_rbac_test.go b/test/openshift/e2e/ginkgo/parallel/1-080_validate_regex_support_argocd_rbac_test.go new file mode 100644 index 000000000..46fb99447 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-080_validate_regex_support_argocd_rbac_test.go @@ -0,0 +1,102 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-080_validate_regex_support_argocd_rbac_test", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that updating ArgoCD CR spec.rbac.policyMatcherMode causes the value to be correctly set on argocd-rbac-cm ConfigMap", func() { + + By("creating a basic Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example-argocd", + Namespace: ns.Name, + }, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("set regex Policy Matcher Mode") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.RBAC.PolicyMatcherMode = ptr.To("regex") + }) + + By("verifying it gets set on argocd-rbac-cm ConfigMap") + argocdRBACCM := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-rbac-cm", + Namespace: ns.Name, + }, + } + Eventually(argocdRBACCM).Should(k8sFixture.ExistByName()) + Eventually(argocdRBACCM).Should(configmapFixture.HaveStringDataKeyValue("policy.matchMode", "regex")) + + By("updating the ConfigMap manually to an invalid value. We don't support users modifying this value manully.") + configmapFixture.Update(argocdRBACCM, func(cm *corev1.ConfigMap) { + cm.Data["policy.matchMode"] = "" + }) + + By("verifying the ConfigMap is reconciled back to the value specified in the ArgoCD CR") + Eventually(argocdRBACCM).Should(configmapFixture.HaveStringDataKeyValue("policy.matchMode", "regex")) + Consistently(argocdRBACCM).Should(configmapFixture.HaveStringDataKeyValue("policy.matchMode", "regex")) + + By("verifying we can also set glob, and it is set in the ConfigMap") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.RBAC.PolicyMatcherMode = ptr.To("glob") + }) + Eventually(argocdRBACCM).Should(configmapFixture.HaveStringDataKeyValue("policy.matchMode", "glob")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-081_validate_applicationset_deployment_test.go b/test/openshift/e2e/ginkgo/parallel/1-081_validate_applicationset_deployment_test.go new file mode 100644 index 000000000..7c48c8b82 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-081_validate_applicationset_deployment_test.go @@ -0,0 +1,67 @@ +/* +Copyright 2021. + +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 parallel + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-081_validate_applicationset_deployment", func() { + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + }) + + It("verifies that openshift-gitops Argo CD has applicationset controller workload and service with expected values", func() { + + gitopsArgoCD, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(gitopsArgoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + appsetController := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-applicationset-controller", Namespace: gitopsArgoCD.Namespace}} + Expect(appsetController).To(k8sFixture.ExistByName()) + Eventually(appsetController).Should(deploymentFixture.HaveReadyReplicas(1)) + + Expect(appsetController.Spec.Template.Spec.Containers[0].Ports).To(Equal([]corev1.ContainerPort{ + {ContainerPort: 7000, Name: "webhook", Protocol: "TCP"}, + {ContainerPort: 8080, Name: "metrics", Protocol: "TCP"}, + })) + + appsetService := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-applicationset-controller", Namespace: gitopsArgoCD.Namespace}, + } + Expect(appsetService).To(k8sFixture.ExistByName()) + Expect(appsetService.Spec.Ports).To(Equal([]corev1.ServicePort{ + {Port: 7000, Name: "webhook", Protocol: "TCP", TargetPort: intstr.FromInt(7000)}, + {Port: 8080, Name: "metrics", Protocol: "TCP", TargetPort: intstr.FromInt(8080)}, + })) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-082_validate_node_placement_test.go b/test/openshift/e2e/ginkgo/parallel/1-082_validate_node_placement_test.go new file mode 100644 index 000000000..525b41a03 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-082_validate_node_placement_test.go @@ -0,0 +1,128 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-082_validate_node_placement", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that setting values in .spec.nodePlacement on Argo CD CR cause those values to be set on the Argo CD Deployment/StatefulSet workloads", func() { + + By("creating a basic Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example-argocd", + Namespace: ns.Name, + }, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("setting ArgoCD .spec.nodePlacement field with 'key1': 'value1'. The operator should set the value on all Argo CD workloads") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.NodePlacement = &argov1beta1api.ArgoCDNodePlacementSpec{ + NodeSelector: map[string]string{ + "key1": "value1", + }, + } + }) + + By("verifying that Argo CD Deployments use the nodeSelector value from ArgoCD CR") + deploymentNameList := []string{"example-argocd-redis", "example-argocd-repo-server", "example-argocd-server"} + + for _, deploymentName := range deploymentNameList { + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deploymentName, Namespace: ns.Name}} + Expect(depl).To(k8sFixture.ExistByName()) + + Eventually(depl).Should(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{"key1": "value1", "kubernetes.io/os": "linux"})) + + } + + By("verifying that Argo CD StatefulSet uses the nodeSelector value from ArgoCD CR") + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-application-controller", Namespace: ns.Name}} + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(statefulSet).Should(statefulsetFixture.HaveTemplateSpecNodeSelector(map[string]string{"key1": "value1", "kubernetes.io/os": "linux"})) + + By("adding a toleration to the nodePlacement in the Argo CD CR") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.NodePlacement = &argov1beta1api.ArgoCDNodePlacementSpec{ + NodeSelector: map[string]string{ + "key1": "value1", + }, + Tolerations: []corev1.Toleration{ + {Key: "key1", Operator: corev1.TolerationOpEqual, Value: "value1", Effect: corev1.TaintEffectNoSchedule}, + }, + } + }) + + By("verifying the Argo CD Deployments are updated to include the toleration change in nodePlacement of CR") + for _, deploymentName := range deploymentNameList { + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deploymentName, Namespace: ns.Name}} + Expect(depl).To(k8sFixture.ExistByName()) + + Eventually(depl).Should(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{"key1": "value1", "kubernetes.io/os": "linux"})) + Eventually(depl).Should(deploymentFixture.HaveTolerations([]corev1.Toleration{{Key: "key1", Operator: corev1.TolerationOpEqual, Value: "value1", Effect: corev1.TaintEffectNoSchedule}})) + + } + + By("verifying the Argo CD StatefulSet is updated to include the toleration change in nodePlacement of CR") + Eventually(statefulSet).Should(k8sFixture.ExistByName()) + Eventually(statefulSet).Should(statefulsetFixture.HaveTemplateSpecNodeSelector(map[string]string{"key1": "value1", "kubernetes.io/os": "linux"})) + + Eventually(statefulSet).Should(statefulsetFixture.HaveTolerations([]corev1.Toleration{{Key: "key1", Operator: corev1.TolerationOpEqual, Value: "value1", Effect: corev1.TaintEffectNoSchedule}})) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-083_validate_kustomize_namereference_test.go b/test/openshift/e2e/ginkgo/parallel/1-083_validate_kustomize_namereference_test.go new file mode 100644 index 000000000..140b3c772 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-083_validate_kustomize_namereference_test.go @@ -0,0 +1,102 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-083_validate_kustomize_namereference", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that when there is a 'configurations:' field in kustomization.yaml with a nameReference in the GitOps repository that it is properly processed and deployed by Argo CD", func() { + + By("creating simple Argo CD instance") + ns, cleanupFunc := fixture.CreateNamespaceWithCleanupFunc("namespace-gitops-2038") + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }} + + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("creating Argo CD Application which uses the configurations and nameReference features in kustomization.yaml") + + app := argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "app-kustomize", Namespace: ns.Name}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/kustomize-example", + RepoURL: "https://github.com/redhat-developer/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: ns.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + }, + }, + } + Expect(k8sClient.Create(ctx, &app)).To(Succeed()) + + By("verifying that the ConfigMap is generated by Kustomize, within Argo CD, and deployed to the Namespace") + configMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "gitops-configmap", Namespace: ns.Name}} + Eventually(configMap, "4m", "5s").Should(k8sFixture.ExistByName()) + + Expect(configMap.Annotations["foo"]).To(Equal("gitops-configmap")) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-083_validate_resource_customization_subkeys_test.go b/test/openshift/e2e/ginkgo/parallel/1-083_validate_resource_customization_subkeys_test.go new file mode 100644 index 000000000..b6f928da7 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-083_validate_resource_customization_subkeys_test.go @@ -0,0 +1,250 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-083_validate_resource_customization_subkeys", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates setting Argo CD CR .spec.resourceIgnoreDifferences/resourceActions/resourceHealthChecks will cause the corresponding setting to be set on argocd-cm ConfigMap", func() { + + By("creating a basic Argo CD instance with .spec.resourceIgnoreDifferences/resourceActions/resourceHealthChecks set with custom values") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCDYAML := ` +metadata: + name: example-argocd +spec: + resourceIgnoreDifferences: + all: + jqPathExpressions: + - xyz + - abc + jsonPointers: + - xyz + - abc + managedFieldsManagers: + - xyz + - abc + resourceIdentifiers: + - group: apps + kind: deployments + customization: + jqPathExpressions: + - xyz + - abc + jsonPointers: + - xyz + - abc + managedFieldsManagers: + - xyz + - abc + - group: batch + kind: jobs + customization: + jqPathExpressions: + - xyz + - abc + jsonPointers: + - xyz + - abc + managedFieldsManagers: + - xyz + - abc + resourceHealthChecks: + - group: certmanager.k8s.io + kind: Certificate + check: | + hs = {} + if obj.status ~= nil then + if obj.status.conditions ~= nil then + for i, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" and condition.status == "False" then + hs.status = "Degraded" + hs.message = condition.message + return hs + end + if condition.type == "Ready" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message + return hs + end + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for certificate" + return hs + resourceActions: + - group: apps + kind: Deployment + action: | + discovery.lua: | + actions = {} + actions["restart"] = {} + return actions + definitions: + - name: restart + # Lua Script to modify the obj + action.lua: | + local os = require("os") + if obj.spec.template.metadata == nil then + obj.spec.template.metadata = {} + end + if obj.spec.template.metadata.annotations == nil then + obj.spec.template.metadata.annotations = {} + end + obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ") + return obj` + + // We unmarshal YAML into ArgoCD CR, so that we don't have to convert it into Go structs (it would be painful) + argoCD := &argov1beta1api.ArgoCD{} + Expect(yaml.UnmarshalStrict([]byte(argoCDYAML), &argoCD)).To(Succeed()) + argoCD.ObjectMeta.Namespace = ns.Name + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("waiting for each of the .data fields of argocd-cm ConfigMap to have expected value") + configMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns.Name}} + Eventually(configMap).Should(k8sFixture.ExistByName()) + + expectedDataFieldYaml := ` + admin.enabled: "true" + application.instanceLabelKey: app.kubernetes.io/instance + application.resourceTrackingMethod: label + configManagementPlugins: "" + ga.anonymizeusers: "false" + ga.trackingid: "" + help.chatText: "" + help.chatUrl: "" + kustomize.buildOptions: "" + oidc.config: "" + repositories: "" + repository.credentials: "" + resource.customizations.actions.apps_Deployment: | + discovery.lua: | + actions = {} + actions["restart"] = {} + return actions + definitions: + - name: restart + # Lua Script to modify the obj + action.lua: | + local os = require("os") + if obj.spec.template.metadata == nil then + obj.spec.template.metadata = {} + end + if obj.spec.template.metadata.annotations == nil then + obj.spec.template.metadata.annotations = {} + end + obj.spec.template.metadata.annotations["kubectl.kubernetes.io/restartedAt"] = os.date("!%Y-%m-%dT%XZ") + return obj + resource.customizations.health.certmanager.k8s.io_Certificate: | + hs = {} + if obj.status ~= nil then + if obj.status.conditions ~= nil then + for i, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" and condition.status == "False" then + hs.status = "Degraded" + hs.message = condition.message + return hs + end + if condition.type == "Ready" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message + return hs + end + end + end + end + hs.status = "Progressing" + hs.message = "Waiting for certificate" + return hs + resource.customizations.ignoreDifferences.all: | + jqpathexpressions: + - xyz + - abc + jsonpointers: + - xyz + - abc + managedfieldsmanagers: + - xyz + - abc + resource.customizations.ignoreDifferences.apps_deployments: | + jqpathexpressions: + - xyz + - abc + jsonpointers: + - xyz + - abc + managedfieldsmanagers: + - xyz + - abc + resource.customizations.ignoreDifferences.batch_jobs: | + jqpathexpressions: + - xyz + - abc + jsonpointers: + - xyz + - abc + managedfieldsmanagers: + - xyz + - abc +` + var expectedDataObj map[string]string + Expect(yaml.Unmarshal([]byte(expectedDataFieldYaml), &expectedDataObj)).To(Succeed()) + + for k, v := range expectedDataObj { + Eventually(configMap).Should(configmapFixture.HaveStringDataKeyValue(k, v), "unable to locate '"+k+"': '"+v+"'") + } + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-084_validate_status_host_ingress_test.go b/test/openshift/e2e/ginkgo/parallel/1-084_validate_status_host_ingress_test.go new file mode 100644 index 000000000..6a048685e --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-084_validate_status_host_ingress_test.go @@ -0,0 +1,93 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-084_validate_status_host_ingress", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that when Argo CD Server is exposed via an Ingress, that the ingress is created and ArgoCD CR has the correct status information", func() { + + By("creating simple Argo CD instance with API Server exposed via ingress") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Host: "test-crane.apps.rh-4.12-111111.dev.openshift.org", + GRPC: argov1beta1api.ArgoCDServerGRPCSpec{ + Ingress: argov1beta1api.ArgoCDIngressSpec{ + Enabled: true, + }, + }, + Ingress: argov1beta1api.ArgoCDIngressSpec{ + Enabled: true, + TLS: []networkingv1.IngressTLS{{Hosts: []string{"test-crane"}}}, + }, + }, + }} + + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying Ingress is created") + serverIngress := &networkingv1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example-argocd-server", + Namespace: ns.Name, + }, + } + Eventually(serverIngress).Should(k8sFixture.ExistByName()) + + By("verifying ArgoCD CR .status references the host from the ArgoCD CR .spec") + Eventually(argoCD).Should(argocdFixture.HaveHost("test-crane.apps.rh-4.12-111111.dev.openshift.org")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-087_validate_repo_server_settings_test.go b/test/openshift/e2e/ginkgo/parallel/1-087_validate_repo_server_settings_test.go new file mode 100644 index 000000000..7e0d1abce --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-087_validate_repo_server_settings_test.go @@ -0,0 +1,169 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-087_validate_repo_server_settings", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that setting mountSAToken and serviceAccount on .spec.repo will cause the values to be set on Repo Server Deployment", func() { + By("creating simple Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("setting 'mountSAToken: false' and 'ServiceAccount: default' on ArgoCD CR .spec.repo") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.MountSAToken = false + ac.Spec.Repo.ServiceAccount = "default" + }) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-repo-server", Namespace: ns.Name}} + + By("verifying expected ArgoCD .spec.repo values are set on Repo server Deployment") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(depl), depl); err != nil { + GinkgoWriter.Println(err) + return false + } + + deplSpecTemplateSpec := depl.Spec.Template.Spec + + if deplSpecTemplateSpec.AutomountServiceAccountToken == nil { + return false + } + + GinkgoWriter.Println("Values:", deplSpecTemplateSpec.ServiceAccountName, deplSpecTemplateSpec.DeprecatedServiceAccount) + + return deplSpecTemplateSpec.ServiceAccountName == "default" && + *deplSpecTemplateSpec.AutomountServiceAccountToken == false && + deplSpecTemplateSpec.DeprecatedServiceAccount == "default" + + }).Should(BeTrue()) + + Eventually(depl, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + + serviceAccount := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "modified-default", Namespace: ns.Name}} + Expect(k8sClient.Create(ctx, serviceAccount)).To(Succeed()) + + By("setting different values, 'mountSAToken: true' and 'serviceAccount: modified-default', values on ArgoCD CR .spec.repo") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.MountSAToken = true + ac.Spec.Repo.ServiceAccount = "modified-default" + }) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying expected .spec.repo values are set on Repo server Deployment") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(depl), depl); err != nil { + GinkgoWriter.Println(err) + return false + } + + deplSpecTemplateSpec := depl.Spec.Template.Spec + + if deplSpecTemplateSpec.AutomountServiceAccountToken == nil { + return false + } + + GinkgoWriter.Println("Values:", deplSpecTemplateSpec.ServiceAccountName, deplSpecTemplateSpec.DeprecatedServiceAccount) + + return deplSpecTemplateSpec.ServiceAccountName == "modified-default" && + *deplSpecTemplateSpec.AutomountServiceAccountToken == true && + deplSpecTemplateSpec.DeprecatedServiceAccount == "modified-default" + + }).Should(BeTrue()) + Eventually(depl, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + + By("reverting mountSAToken and ServiceAccount values on ArgoCD CR .spec.repo to default") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Repo.MountSAToken = false + ac.Spec.Repo.ServiceAccount = "" + }) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying expected .spec.repo values are set on Repo server Deployment") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(depl), depl); err != nil { + GinkgoWriter.Println(err) + return false + } + + deplSpecTemplateSpec := depl.Spec.Template.Spec + + if deplSpecTemplateSpec.AutomountServiceAccountToken == nil { + return false + } + + return *deplSpecTemplateSpec.AutomountServiceAccountToken == false + + }).Should(BeTrue()) + Eventually(depl, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-095_validate_dex_clientsecret_test.go b/test/openshift/e2e/ginkgo/parallel/1-095_validate_dex_clientsecret_test.go new file mode 100644 index 000000000..647234965 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-095_validate_dex_clientsecret_test.go @@ -0,0 +1,121 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-095_validate_dex_clientsecret", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that Dex serviceaccount token secret is not leaked, and is correctly set in Argo CD argocd-secret Secret", func() { + + By("creating simple Argo CD instance with Dex and Openshift OAuth enabled") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + SSO: &argov1beta1api.ArgoCDSSOSpec{ + Provider: argov1beta1api.SSOProviderTypeDex, + Dex: &argov1beta1api.ArgoCDDexSpec{ + OpenShiftOAuth: true, + }, + }, + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + serviceAccount := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-argocd-dex-server", Namespace: ns.Name}} + Eventually(serviceAccount).Should(k8sFixture.ExistByName()) + + argocdCM := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns.Name}, + } + Eventually(argocdCM).Should(k8sFixture.ExistByName()) + + By("verifying argocd-cm ConfigMap is not leaking oidc dex client secret") + dexConfig := argocdCM.Data["dex.config"] + + Expect(dexConfig).To(ContainSubstring("clientSecret: $oidc.dex.clientSecret"), "'$oidc.dex.clientSecret' should be set. Any other value implies that the client secret is exposed via ConfigMap") + + By("validating that the Dex Client Secret was copied from dex serviceaccount token secret in to argocd-secret, by the operator") + + // To verify the behavior we should first get the token secret name of the dex service account. + + var secretName string + for _, secretData := range serviceAccount.Secrets { + + if strings.Contains(secretData.Name, "token") { + secretName = secretData.Name + } + } + Expect(secretName).ToNot(BeEmpty()) + + // Extract the clientSecret + secretReferencedFromServiceAccount := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: secretName, Namespace: ns.Name}} + Eventually(secretReferencedFromServiceAccount).Should(k8sFixture.ExistByName()) + tokenFromSASecret := secretReferencedFromServiceAccount.Data["token"] + Expect(tokenFromSASecret).ToNot(BeEmpty()) + + // actualClientSecret is the value of the secret in argocd-secret where argocd-operator should copy the secret from + argocdSecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "argocd-secret", Namespace: ns.Name}} + Eventually(argocdSecret).Should(k8sFixture.ExistByName()) + + actualClientSecret := argocdSecret.Data["oidc.dex.clientSecret"] + + Expect(string(actualClientSecret)).To(Equal(string(tokenFromSASecret)), "Dex Client Secret for OIDC is not valid") + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-099_validate_server_autoscale_test.go b/test/openshift/e2e/ginkgo/parallel/1-099_validate_server_autoscale_test.go new file mode 100644 index 000000000..d1580d41e --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-099_validate_server_autoscale_test.go @@ -0,0 +1,189 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + autoscalingv1 "k8s.io/api/autoscaling/v1" + autoscalingv2 "k8s.io/api/autoscaling/v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-099_validate_server_autoscale", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("varies that setting ArgoCD CR Server replicas and autoscaling affect the corresponding Deployment and HPA values", func() { + + By("creating simple Argo CD instance with 2 server replicas") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Replicas: ptr.To(int32(2)), + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying Argo CD Server component Deployment has expected values from ArgoCD CR") + + serverDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-server", Namespace: ns.Name}} + Eventually(serverDepl).Should(k8sFixture.ExistByName()) + Expect(*serverDepl.Spec.Replicas).To(Equal(int32(2))) + + By("verifying Deployment is Available") + Eventually(serverDepl).Should(deploymentFixture.HaveConditionTypeStatus(appsv1.DeploymentAvailable, corev1.ConditionTrue)) + Eventually(serverDepl).Should(deploymentFixture.HaveConditionTypeStatus(appsv1.DeploymentProgressing, corev1.ConditionTrue)) + + By("enabling Argo CD Server autoscaling") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.Autoscale = argov1beta1api.ArgoCDServerAutoscaleSpec{ + Enabled: true, + HPA: &autoscalingv1.HorizontalPodAutoscalerSpec{ + MinReplicas: ptr.To(int32(4)), + MaxReplicas: int32(7), + TargetCPUUtilizationPercentage: ptr.To(int32(50)), + ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{ + Kind: "deployment", + APIVersion: "apps/v1", + Name: "example-argocd-server", + }, + }, + } + }) + + By("verifying autoscaling values are set on Server Deployment replicas") + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(serverDepl), serverDepl); err != nil { + GinkgoWriter.Println(err) + return false + } + + replicas := *serverDepl.Spec.Replicas + GinkgoWriter.Println("serverDepl replicas", replicas) + + return replicas >= 4 && replicas <= 7 + }, "1m", "5s").Should(BeTrue(), "server replica count should match expectation") + + By("updating the autoscaling values on Argo CD CR") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.Autoscale = argov1beta1api.ArgoCDServerAutoscaleSpec{ + Enabled: true, + HPA: &autoscalingv1.HorizontalPodAutoscalerSpec{ + MinReplicas: ptr.To(int32(8)), + MaxReplicas: int32(12), + TargetCPUUtilizationPercentage: ptr.To(int32(50)), + ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{ + Kind: "deployment", + APIVersion: "apps/v1", + Name: "example-argocd-server", + }, + }, + } + }) + + By("verifying that the values set on ArgoCD CR are eventually set on the example-argocd-server HPA") + hpa := &autoscalingv2.HorizontalPodAutoscaler{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-server", Namespace: ns.Name}, + } + Eventually(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(hpa), hpa); err != nil { + GinkgoWriter.Println(err) + return false + } + + if hpa.Spec.MaxReplicas != int32(12) { + GinkgoWriter.Println(hpa.Spec.MaxReplicas) + return false + } + + if *hpa.Spec.MinReplicas != int32(8) { + GinkgoWriter.Println(hpa.Spec.MinReplicas) + return false + } + + str := hpa.Spec.ScaleTargetRef + if str.APIVersion != "apps/v1" || str.Kind != "deployment" || str.Name != "example-argocd-server" { + GinkgoWriter.Println(str) + return false + } + + if len(hpa.Spec.Metrics) != 1 { + GinkgoWriter.Println(len(hpa.Spec.Metrics)) + return false + } + + metric := hpa.Spec.Metrics[0] + + if metric.Resource == nil { + GinkgoWriter.Println(metric.Resource) + return false + } + + if metric.Resource.Name != "cpu" { + GinkgoWriter.Println(metric.Resource.Name) + return false + } + + if *metric.Resource.Target.AverageUtilization != int32(50) { + GinkgoWriter.Println(*metric.Resource.Target.AverageUtilization) + return false + } + if metric.Resource.Target.Type != autoscalingv2.UtilizationMetricType { + GinkgoWriter.Println(metric.Resource.Target.Type) + return false + } + + return true + + }).Should(BeTrue()) + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-102_validate_handle_terminating_namespaces_test.go b/test/openshift/e2e/ginkgo/parallel/1-102_validate_handle_terminating_namespaces_test.go new file mode 100644 index 000000000..3ad813191 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-102_validate_handle_terminating_namespaces_test.go @@ -0,0 +1,166 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + appFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + configmapFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/configmap" + namespaceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/namespace" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-102_validate_handle_terminating_namespaces", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that if one managed-by namespace is stuck in terminating, it does not prevent other managed-by namespaces from being managed or deployed to", func() { + + By("creating simple namespace-scoped Argo CD instance") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("creating a namespace 'jane' containing a ConfigMap with a unowned finalizer") + janeNs, cleanupFunc := fixture.CreateManagedNamespaceWithCleanupFunc("jane", ns.Name) + defer cleanupFunc() + + configMapJaneNs := corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: "my-config-map-2", Namespace: janeNs.Name, Finalizers: []string{"some.random/finalizer"}}, + } + Expect(k8sClient.Create(ctx, &configMapJaneNs)).To(Succeed()) + + // At the end of the test, ensure the ConfigMap finalizer is removed so that the namespace is cleaned up + defer func() { + configmapFixture.Update(&configMapJaneNs, func(cm *corev1.ConfigMap) { + cm.ObjectMeta.Finalizers = nil + }) + }() + + By("deleting the jane NS in a background go routine, which puts the jane NS into a simulated stuck in terminating state") + go func() { + defer GinkgoRecover() + Expect(k8sClient.Delete(ctx, &janeNs)).To(Succeed()) + }() + + By("verifying jane ns moves into terminating state") + Eventually(&janeNs).Should(namespaceFixture.HavePhase(corev1.NamespaceTerminating)) + + By("creating John NS") + johnNs, cleanupFunc := fixture.CreateManagedNamespaceWithCleanupFunc("john", ns.Name) + defer cleanupFunc() + + By("Wait for managed-by rolebindings to be created in John NS") + Eventually(func() bool { + var roleBindingList rbacv1.RoleBindingList + if err := k8sClient.List(ctx, &roleBindingList, &client.ListOptions{Namespace: johnNs.Name}); err != nil { + GinkgoWriter.Println(err) + return false + } + + match := false + for _, roleBinding := range roleBindingList.Items { + if strings.Contains(roleBinding.Name, "argocd-argocd-server") { + match = true + break + } + } + if !match { + GinkgoWriter.Println("argocd-server RoleBinding not yet found") + return false + } + + match = false + for _, roleBinding := range roleBindingList.Items { + if strings.Contains(roleBinding.Name, "argocd-application-controller") { + match = true + break + } + } + if !match { + GinkgoWriter.Println("argocd-application-controller RoleBinding not yet found") + return false + } + + return true + }).Should(BeTrue()) + + By("creating a test Argo CD Application targeting john NS") + + app := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "my-app", Namespace: ns.Name}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/kustomize-guestbook", + RepoURL: "https://github.com/redhat-developer/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: johnNs.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{ + Prune: true, + SelfHeal: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("verifying Argo CD is successfully able to deploy to the John Namespace") + + Eventually(app, "4m", "5s").Should(appFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-103_argocd_alpha_to_beta_conversion_test.go b/test/openshift/e2e/ginkgo/parallel/1-103_argocd_alpha_to_beta_conversion_test.go new file mode 100644 index 000000000..3c12bbcc7 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-103_argocd_alpha_to_beta_conversion_test.go @@ -0,0 +1,95 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1alpha1api "github.com/argoproj-labs/argocd-operator/api/v1alpha1" + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-103_argocd_alpha_to_beta_conversion", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that creation of a v1alpha1 ArgoCD CR with SSO fields will be translated into a v1beta1 ArgoCD CR via webhook", func() { + if fixture.EnvLocalRun() { + Skip("When LOCAL_RUN is set, the API upgrade webhook is not running, which is what this test tets. Thus this test should be skipped.") + return + } + + By("creating a v1alpha1-API-version Argo CD instance, with Dex SSO fields") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + oldArgoCD := &argov1alpha1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1alpha1api.ArgoCDSpec{ + Dex: &argov1alpha1api.ArgoCDDexSpec{ + OpenShiftOAuth: true, + }, + Server: argov1alpha1api.ArgoCDServerSpec{ + Route: argov1alpha1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, oldArgoCD)).To(Succeed()) + + By("retrieving the ArgoCD CR using the v1beta1 API") + newArgoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + } + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(newArgoCD), newArgoCD)).To(Succeed()) + + By("verifying the fields were translated successfully via the webhook, from v1alpha1 to v1beta") + Expect(newArgoCD.Spec.SSO).ToNot(BeNil()) + Expect(newArgoCD.Spec.SSO.Provider).To(Equal(argov1beta1api.SSOProviderTypeDex)) + + Expect(newArgoCD.Spec.SSO.Dex).ToNot(BeNil()) + Expect(newArgoCD.Spec.SSO.Dex.OpenShiftOAuth).To(BeTrue()) + + Expect(newArgoCD.Spec.Server.Route.Enabled).To(BeTrue()) + + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.HaveSSOStatus("Running")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-104_validate_applicationset_tls_scm_volume_mount_test.go b/test/openshift/e2e/ginkgo/parallel/1-104_validate_applicationset_tls_scm_volume_mount_test.go new file mode 100644 index 000000000..0ee49ff3c --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-104_validate_applicationset_tls_scm_volume_mount_test.go @@ -0,0 +1,210 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-104_validate_applicationset_tls_scm_volume_mount", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that specifying a ConfigMap to ArgoCD CR .spec.applicationSet.SCMRootCAConfigMap will cause that ConfigMap to be mounted into applicationset controller Deployment, and that applicationset controller has expected volumes and mounts", func() { + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + By("creating a certificate in a ConfigMap that we expect to be mounted into applicationset controller Deployment") + configMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: "test-1-104-appsets-scm-tls-cm", Namespace: ns.Name}, + Data: map[string]string{ + "cert": `-----BEGIN CERTIFICATE----- +AIIEBCCA7+gAwIBAgIUQdTcSHY2Sxd3Tq/v1eIEZPCNbOowDQYJKoZIhvcNAQEL +BQAwezELMAkGA1UEBhMCREUxFTATBgNVBAgMDExvd2VyIFNheG9ueTEQMA4GA1UE +BwwHSGFub3ZlcjEVMBMGA1UECgwMVGVzdGluZyBDb3JwMRIwEAYDVQQLDAlUZXN0 +c3VpdGUxGDAWBrNVBAMMD2Jhci5leGFtcGxlLmNvbTAeFw0xOTA3MDgxMzU2MTda +Fw0yMDA3MDcxMzU2MTdaMHsxCzAJBgNVBAYTAkRFMRUwEwYDVQQIDAxMb3dlciBT +YXhvbnkxEDAOBgNVBAcMB0hhbm92ZXIxFTATBgNVBAoMDFRlc3RpbmcgQ29ycDES +MBAGA1UECwwJVGVzdHN1aXRlMRgwFgYDVQQDDA9iYXIuZXhhbXBsZS5jb20wggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCv4mHMdVUcafmaSHVpUM0zZWp5 +NFXfboxA4inuOkE8kZlbGSe7wiG9WqLirdr39Ts+WSAFA6oANvbzlu3JrEQ2CHPc +CNQm6diPREFwcDPFCe/eMawbwkQAPVSHPts0UoRxnpZox5pn69ghncBR+jtvx+/u +P6HdwW0qqTvfJnfAF1hBJ4oIk2AXiip5kkIznsAh9W6WRy6nTVCeetmIepDOGe0G +ZJIRn/OfSz7NzKylfDCat2z3EAutyeT/5oXZoWOmGg/8T7pn/pR588GoYYKRQnp+ +YilqCPFX+az09EqqK/iHXnkdZ/Z2fCuU+9M/Zhrnlwlygl3RuVBI6xhm/ZsXtL2E +Gxa61lNy6pyx5+hSxHEFEJshXLtioRd702VdLKxEOuYSXKeJDs1x9o6cJ75S6hko +Ml1L4zCU+xEsMcvb1iQ2n7PZdacqhkFRUVVVmJ56th8aYyX7KNX6M9CD+kMpNm6J +kKC1li/Iy+RI138bAvaFplajMF551kt44dSvIoJIbTr1LigudzWPqk31QaZXV/4u +kD1n4p/XMc9HYU/was/CmQBFqmIZedTLTtK7clkuFN6wbwzdo1wmUNgnySQuMacO +gxhHxxzRWxd24uLyk9Px+9U3BfVPaRLiOPaPoC58lyVOykjSgfpgbus7JS69fCq7 +bEH4Jatp/10zkco+UQIDAQABo1MwUTAdBgNVHQ4EFgQUjXH6PHi92y4C4hQpey86 +r6+x1ewwHwYDVR0jBBgwFoAUjXH6PHi92y4C4hQpey86r6+x1ewwDwYDVR0TAQH/ +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAFE4SdKsX9UsLy+Z0xuHSxhTd0jfn +Iih5mtzb8CDNO5oTw4z0aMeAvpsUvjJ/XjgxnkiRACXh7K9hsG2r+ageRWGevyvx +CaRXFbherV1kTnZw4Y9/pgZTYVWs9jlqFOppz5sStkfjsDQ5lmPJGDii/StENAz2 +XmtiPOgfG9Upb0GAJBCuKnrU9bIcT4L20gd2F4Y14ccyjlf8UiUi192IX6yM9OjT ++TuXwZgqnTOq6piVgr+FTSa24qSvaXb5z/mJDLlk23npecTouLg83TNSn3R6fYQr +d/Y9eXuUJ8U7/qTh2Ulz071AO9KzPOmleYPTx4Xty4xAtWi1QE5NHW9/Ajlv5OtO +OnMNWIs7ssDJBsB7VFC8hcwf79jz7kC0xmQqDfw51Xhhk04kla+v+HZcFW2AO9so +6ZdVHHQnIbJa7yQJKZ+hK49IOoBR6JgdB5kymoplLLiuqZSYTcwSBZ72FYTm3iAr +jzvt1hxpxVDmXvRnkhRrIRhK4QgJL0jRmirBjDY+PYYd7bdRIjN7WNZLFsgplnS8 +9w6CwG32pRlm0c8kkiQ7FXA6BYCqOsDI8f1VGQv331OpR2Ck+FTv+L7DAmg6l37W +AIIEBCCA7+gAwIBAgIUQdTcSHY2Sxd3Tq/v1eIEZPCNbOowDQYJKoZIhvcNAQEL +XWyb96wrUlv+E8I= +-----END CERTIFICATE-----`, + }, + } + Expect(k8sClient.Create(ctx, configMap)).To(Succeed()) + + By("creating simple Argo CD instance that references the ConfigMap via .spec.applicationSet.scmRootCAConfigMap ") + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + ApplicationSet: &argov1beta1api.ArgoCDApplicationSet{ + SCMRootCAConfigMap: configMap.Name, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting for ArgoCD CR to be reconciled and the instance to be ready") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("expecting application set controller to be running with parameter that references the cert via volume mount path") + + appsetDepl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-applicationset-controller", Namespace: ns.Name}, + } + Expect(appsetDepl).To(deploymentFixture.HaveContainerCommandSubstring("--scm-root-ca-path /app/tls/scm/cert", 0)) + + By("expecting that volume mount is mapped into container") + container := deploymentFixture.GetTemplateSpecContainerByName("argocd-applicationset-controller", *appsetDepl) + Expect(container).ToNot(BeNil()) + + volumeMountMatch := false + for _, vm := range container.VolumeMounts { + if vm.Name == "appset-gitlab-scm-tls-cert" && vm.MountPath == "/app/tls/scm/" { + volumeMountMatch = true + break + } + } + Expect(volumeMountMatch).To(BeTrue()) + + By("expecting that ConfigMap is mounted into deployment as a volume") + volumeMatch := false + for _, v := range appsetDepl.Spec.Template.Spec.Volumes { + if v.Name == "appset-gitlab-scm-tls-cert" { + if v.ConfigMap != nil { + + if *v.ConfigMap.DefaultMode == 420 && v.ConfigMap.Name == "argocd-appset-gitlab-scm-tls-certs-cm" { + volumeMatch = true + } + } + } + } + Expect(volumeMatch).To(BeTrue()) + + By("verifying volumemounts and volumes of Argo CD ApplicationSet controller") + + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(appsetDepl), appsetDepl)).To(Succeed()) + + Expect(appsetDepl.ObjectMeta.Labels["app.kubernetes.io/component"]).To(Equal("controller")) + Expect(appsetDepl.ObjectMeta.Labels["app.kubernetes.io/managed-by"]).To(Equal("argocd")) + Expect(appsetDepl.ObjectMeta.Labels["app.kubernetes.io/name"]).To(Equal("argocd-applicationset-controller")) + Expect(appsetDepl.ObjectMeta.Labels["app.kubernetes.io/part-of"]).To(Equal("argocd")) + + Expect(appsetDepl.Spec.Template.Spec.Containers[0].VolumeMounts).To(Equal([]corev1.VolumeMount{ + {Name: "ssh-known-hosts", MountPath: "/app/config/ssh"}, + {Name: "tls-certs", MountPath: "/app/config/tls"}, + {Name: "gpg-keys", MountPath: "/app/config/gpg/source"}, + {Name: "gpg-keyring", MountPath: "/app/config/gpg/keys"}, + {Name: "tmp", MountPath: "/tmp"}, + {Name: "appset-gitlab-scm-tls-cert", MountPath: "/app/tls/scm/"}, + })) + + Expect(appsetDepl.Spec.Template.Spec.Volumes).To(Equal([]corev1.Volume{ + { + Name: "ssh-known-hosts", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-ssh-known-hosts-cm"}}, + }, + }, + { + Name: "tls-certs", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-tls-certs-cm"}}, + }, + }, + { + Name: "gpg-keys", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-gpg-keys-cm"}}, + }, + }, + { + Name: "gpg-keyring", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "tmp", VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + }, + { + Name: "appset-gitlab-scm-tls-cert", VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + DefaultMode: ptr.To(int32(420)), + LocalObjectReference: corev1.LocalObjectReference{Name: "argocd-appset-gitlab-scm-tls-certs-cm"}}, + }, + }, + })) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-105_validate_default_argocd_route_test.go b/test/openshift/e2e/ginkgo/parallel/1-105_validate_default_argocd_route_test.go new file mode 100644 index 000000000..95d57404a --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-105_validate_default_argocd_route_test.go @@ -0,0 +1,127 @@ +/* +Copyright 2021. + +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 parallel + +import ( + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + routev1 "github.com/openshift/api/route/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + routeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/route" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/utils/ptr" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-105_validate_default_argocd_route", func() { + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + }) + + It("ensure that openshift-gitops Argo CD has correct default settings, and those settings can be changed which will affect the server Route", func() { + + By("verifying Argo CD in openshift-gitops exists and has server route enabled") + + argoCD, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + + Eventually(argoCD, "4m", "5s").Should(argocdFixture.BeAvailable()) + + Expect(argoCD.Spec.Server.Route.Enabled).To(BeTrue()) + + By("verify the argocd-server-tls secret is created by the OpenShift's service CA") + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-server-tls", + Namespace: argoCD.Namespace, + }, + } + Eventually(secret).Should(k8sFixture.ExistByName()) + Expect(secret.Type).To(Equal(corev1.SecretTypeTLS)) + + By("verifying gitops server Route exists in openshift-gitops, and has expected default settings") + serverRoute := &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-server", Namespace: "openshift-gitops"}, + } + Eventually(serverRoute).Should(k8sFixture.ExistByName()) + + Eventually(serverRoute).Should(routeFixture.HavePort(intstr.FromString("https"))) + Eventually(serverRoute).Should(routeFixture.HaveTLS(routev1.TLSTerminationReencrypt, routev1.InsecureEdgeTerminationPolicyRedirect)) + + Eventually(serverRoute).Should(routeFixture.HaveTo(routev1.RouteTargetReference{ + Kind: "Service", + Name: "openshift-gitops-server", + Weight: ptr.To(int32(100)), + })) + + By("verifying Route ingress has been admitted") + Eventually(serverRoute).Should(routeFixture.HaveConditionTypeStatus(routev1.RouteAdmitted, corev1.ConditionTrue)) + + By("updating Argo CD to use diffferent Termination and InsecureEdgeTerminationPolicy values") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.Route = argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + TLS: &routev1.TLSConfig{ + Termination: routev1.TLSTerminationPassthrough, + InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyNone, + }, + } + }) + + defer func() { + By("cleaning up openshift-gitops ArgoCD back to default, after test runs") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Server.Route = argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + TLS: &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect, + }, + } + }) + }() + + By("verifying ArgoCD CR is reconciled to the new values") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying Argo CD server Route has picked up the new passthrough and insecure termination values") + Eventually(serverRoute).Should(k8sFixture.ExistByName()) + + Eventually(serverRoute).Should(routeFixture.HavePort(intstr.FromString("https"))) + Eventually(serverRoute).Should(routeFixture.HaveTLS(routev1.TLSTerminationPassthrough, routev1.InsecureEdgeTerminationPolicyNone)) + + Eventually(serverRoute).Should(routeFixture.HaveTo(routev1.RouteTargetReference{ + Kind: "Service", + Name: "openshift-gitops-server", + Weight: ptr.To(int32(100)), + })) + + Eventually(serverRoute).Should(routeFixture.HaveConditionTypeStatus(routev1.RouteAdmitted, corev1.ConditionTrue)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-106_validate_appcontroller_initcontainers_test.go b/test/openshift/e2e/ginkgo/parallel/1-106_validate_appcontroller_initcontainers_test.go new file mode 100644 index 000000000..21c6d339e --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-106_validate_appcontroller_initcontainers_test.go @@ -0,0 +1,102 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + podFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/pod" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-106_validate_appcontroller_initcontainers", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + + }) + + It("verifies that setting .spec.controller.initContainers on Argo CD CR will cause that init container to be set on application controller StatefulSet", func() { + + By("creating an ArgoCD CR with an init container for application controller") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Controller: argov1beta1api.ArgoCDApplicationControllerSpec{ + InitContainers: []corev1.Container{{ + Name: "argocd-init", + Image: "nginx:latest", + ImagePullPolicy: corev1.PullAlways, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, + }}, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting the for Argo CD Application Controller Pod to be available") + appControllerPod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller-0", Namespace: ns.Name}} + Eventually(appControllerPod, "3m", "5s").Should(k8sFixture.ExistByName()) + + By("verifying that init container within Pod has the same value that we set in Argo CD CR") + initContainer := podFixture.GetSpecInitContainerByName("argocd-init", *appControllerPod) + Expect(initContainer).ToNot(BeNil()) + + Expect(initContainer.Image).To(Equal("nginx:latest")) + Expect(initContainer.ImagePullPolicy).To(Equal(corev1.PullAlways)) + Expect(initContainer.Resources.Limits.Cpu().String()).To(Equal("50m")) + Expect(initContainer.Resources.Limits.Memory().String()).To(Equal("64Mi")) + + Expect(initContainer.Resources.Requests.Cpu().String()).To(Equal("10m")) + Expect(initContainer.Resources.Requests.Memory().String()).To(Equal("32Mi")) + + Expect(appControllerPod.Spec.Containers[0].Name).To(Equal("argocd-application-controller")) + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-107_validate_server_initcontainers_test.go b/test/openshift/e2e/ginkgo/parallel/1-107_validate_server_initcontainers_test.go new file mode 100644 index 000000000..429868286 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-107_validate_server_initcontainers_test.go @@ -0,0 +1,104 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-107_validate_server_initcontainers", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + + }) + + It("verifies that setting .spec.server.initContainers on Argo CD CR will cause that init container to be set on server Deployment", func() { + + By("creating an ArgoCD CR with an init container for server") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + InitContainers: []corev1.Container{{ + Name: "argocd-init", + Image: "nginx:latest", + ImagePullPolicy: corev1.PullAlways, + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, + }}, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting the for Argo CD Server Deployment to exist") + serverDeployment := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: ns.Name}} + Eventually(serverDeployment, "3m", "5s").Should(k8sFixture.ExistByName()) + + By("verifying that init container within the Server Deployment has the same values that we set in Argo CD CR") + initContainer := deploymentFixture.GetTemplateSpecInitContainerByName("argocd-init", *serverDeployment) + Expect(initContainer).ToNot(BeNil()) + + Expect(initContainer.Image).To(Equal("nginx:latest")) + Expect(initContainer.ImagePullPolicy).To(Equal(corev1.PullAlways)) + Expect(initContainer.Resources.Limits.Cpu().String()).To(Equal("50m")) + Expect(initContainer.Resources.Limits.Memory().String()).To(Equal("64Mi")) + + Expect(initContainer.Resources.Requests.Cpu().String()).To(Equal("10m")) + Expect(initContainer.Resources.Requests.Memory().String()).To(Equal("32Mi")) + + Expect(serverDeployment.Spec.Template.Spec.Containers[0].Name).To(Equal("argocd-server")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-108_validate_appcontroller_sidecar_test.go b/test/openshift/e2e/ginkgo/parallel/1-108_validate_appcontroller_sidecar_test.go new file mode 100644 index 000000000..2338ef6ff --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-108_validate_appcontroller_sidecar_test.go @@ -0,0 +1,103 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + podFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/pod" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-108_validate_appcontroller_sidecar", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + + }) + + It("verifies that setting a sidecar in application controller via ArgoCD CR will cause that sidecar to appear in application controller StatefulSet", func() { + + By("creating an ArgoCD CR with a sidecar in the application controller") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Controller: argov1beta1api.ArgoCDApplicationControllerSpec{ + SidecarContainers: []corev1.Container{{ + Name: "sidecar", + Image: "quay.io/fedora/fedora:latest", + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, + }}, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting the for Argo CD Application Controller Pod to be available") + appControllerPod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller-0", Namespace: ns.Name}} + Eventually(appControllerPod, "3m", "5s").Should(k8sFixture.ExistByName()) + + By("verifying that sidecar container within Pod has the same value that we set in Argo CD CR") + + sidecarContainer := podFixture.GetSpecContainerByName("sidecar", *appControllerPod) + Expect(sidecarContainer).ToNot(BeNil()) + + Expect(appControllerPod.Spec.Containers[0].Name).To(Equal("argocd-application-controller")) + + Expect(sidecarContainer.Name).To(Equal("sidecar")) + Expect(sidecarContainer.Image).To(Equal("quay.io/fedora/fedora:latest")) + Expect(sidecarContainer.Resources.Limits.Cpu().String()).To(Equal("50m")) + Expect(sidecarContainer.Resources.Limits.Memory().String()).To(Equal("64Mi")) + + Expect(sidecarContainer.Resources.Requests.Cpu().String()).To(Equal("10m")) + Expect(sidecarContainer.Resources.Requests.Memory().String()).To(Equal("32Mi")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/1-109_validate_server_sidecar_test.go b/test/openshift/e2e/ginkgo/parallel/1-109_validate_server_sidecar_test.go new file mode 100644 index 000000000..169980ca3 --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/1-109_validate_server_sidecar_test.go @@ -0,0 +1,104 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Parallel E2E Tests", func() { + + Context("1-109_validate_server_sidecar", func() { + + var ( + k8sClient client.Client + ctx context.Context + ) + + BeforeEach(func() { + fixture.EnsureParallelCleanSlate() + + k8sClient, _ = fixtureUtils.GetE2ETestKubeClient() + ctx = context.Background() + + }) + + It("verifies that setting a sidecar in server via ArgoCD CR will cause that sidecar to appear in server Deployment", func() { + + By("creating an ArgoCD CR with a sidecar in the application controller") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + SidecarContainers: []corev1.Container{{ + Name: "sidecar", + Image: "quay.io/fedora/fedora:latest", + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("50m"), + corev1.ResourceMemory: resource.MustParse("64Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("32Mi"), + }, + }, + }}, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("waiting the for Argo CD Application Controller Pod to be available") + serverDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: ns.Name}} + Eventually(serverDepl, "3m", "5s").Should(k8sFixture.ExistByName()) + + By("verifying that sidecar container within Pod has the same value that we set in Argo CD CR") + + sidecarContainer := deploymentFixture.GetTemplateSpecContainerByName("sidecar", *serverDepl) + Expect(sidecarContainer).ToNot(BeNil()) + + Expect(sidecarContainer.Name).To(Equal("sidecar")) + Expect(sidecarContainer.Image).To(Equal("quay.io/fedora/fedora:latest")) + Expect(sidecarContainer.Resources.Limits.Cpu().String()).To(Equal("50m")) + Expect(sidecarContainer.Resources.Limits.Memory().String()).To(Equal("64Mi")) + + Expect(sidecarContainer.Resources.Requests.Cpu().String()).To(Equal("10m")) + Expect(sidecarContainer.Resources.Requests.Memory().String()).To(Equal("32Mi")) + + Expect(serverDepl.Spec.Template.Spec.Containers[0].Name).To(Equal("argocd-server")) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/parallel/suite_test.go b/test/openshift/e2e/ginkgo/parallel/suite_test.go new file mode 100644 index 000000000..28266e71c --- /dev/null +++ b/test/openshift/e2e/ginkgo/parallel/suite_test.go @@ -0,0 +1,51 @@ +/* +Copyright 2021. + +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 parallel + +import ( + "testing" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + _ "k8s.io/client-go/plugin/pkg/client/auth" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +func TestSequentialSuite(t *testing.T) { + + RegisterFailHandler(Fail) + RunSpecs(t, "Parallel Test Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + // Before the test starts, ensure that operator is restored to default state, and all previous sequential/parallel test resources are deleted + fixture.EnsureSequentialCleanSlate() +}) + +var _ = AfterSuite(func() { +}) diff --git a/test/openshift/e2e/ginkgo/sequential/.gitignore b/test/openshift/e2e/ginkgo/sequential/.gitignore new file mode 100644 index 000000000..801bbb9a4 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/.gitignore @@ -0,0 +1 @@ +ginkgo.report diff --git a/test/openshift/e2e/ginkgo/sequential/1-002-validate_backend_service_test.go b/test/openshift/e2e/ginkgo/sequential/1-002-validate_backend_service_test.go new file mode 100644 index 000000000..a14faeb06 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-002-validate_backend_service_test.go @@ -0,0 +1,37 @@ +package sequential + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-002-validate_backend_service", func() { + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + }) + + It("validates backend service permissions", func() { + + By("checking the openshift-gitops namespace installed by default") + Eventually(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + By("checking we have a cluster deployment in the namespace") + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl, "60s", "3s").Should(deploymentFixture.HaveReplicas(1)) + Eventually(depl, "60s", "3s").Should(deploymentFixture.HaveReadyReplicas(1)) + + By("checking Service for cluster exists") + Eventually(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}}, "60s", "5s").Should(k8sFixture.ExistByName()) + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-008_validate-4.9CI-Failures_test.go b/test/openshift/e2e/ginkgo/sequential/1-008_validate-4.9CI-Failures_test.go new file mode 100644 index 000000000..4a493332a --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-008_validate-4.9CI-Failures_test.go @@ -0,0 +1,176 @@ +/* +Copyright 2021. + +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 sequential + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + argocdv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + applicationFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/application" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + + "github.com/argoproj/gitops-engine/pkg/health" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-008_validate-4.9CI-Failures", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies 4.9 CI failures", func() { + + sourceNS := fixture.CreateNamespace("source-ns") + + By("creating simple namespace-scoped ArgoCD instance with route enabled") + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: sourceNS.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + By("creating target-ns namespace which we will deploy into") + targetNS := fixture.CreateManagedNamespace("target-ns", sourceNS.Name) + + Eventually(argoCD, "4m", "5s").Should(argocdFixture.HavePhase("Available")) + + By("ensuring default AppProject exists in source-ns") + appProject := &argocdv1alpha1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: sourceNS.Name}, + } + Eventually(appProject, "1m", "5s").Should(k8sFixture.ExistByName()) + + By("ensuring Roles are created in target-ns, which indicates that it is successfully managed") + role := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: targetNS.Name}, + } + Eventually(role, "1m", "5s").Should(k8sFixture.ExistByName()) + role = &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: targetNS.Name}, + } + Eventually(role, "1m", "5s").Should(k8sFixture.ExistByName()) + + roleBinding := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: targetNS.Name}, + } + Eventually(roleBinding, "1m", "5s").Should(k8sFixture.ExistByName()) + + roleBinding = &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: targetNS.Name}, + } + Eventually(roleBinding, "1m", "5s").Should(k8sFixture.ExistByName()) + + By("creating unrestricted role/rolebinding in source-ns NS for source-ns application-controller ServiceAccount") + sourceNSRoleCreate := rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{Name: "source-ns-openshift-gitops-argocd-application-controller", Namespace: sourceNS.Name}, + Rules: []rbacv1.PolicyRule{{ + APIGroups: []string{"*"}, + Resources: []string{"*"}, + Verbs: []string{"*"}, + }}, + } + Expect(k8sClient.Create(ctx, &sourceNSRoleCreate)).To(Succeed()) + + sourceNSRoleBindingCreate := rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "source-ns-openshift-gitops-argocd-application-controller", Namespace: sourceNS.Name}, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "source-ns-openshift-gitops-argocd-application-controller", + }, + Subjects: []rbacv1.Subject{{Kind: "ServiceAccount", Name: "argocd-argocd-application-controller"}}, + } + Expect(k8sClient.Create(ctx, &sourceNSRoleBindingCreate)).To(Succeed()) + + By("verifying the role and rolebinding that we created exist") // Not entirely sure why we do this, but I ported it over from the old kuttl test + sourceNSRole := rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{Name: "source-ns-openshift-gitops-argocd-application-controller", Namespace: sourceNS.Name}, + } + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(&sourceNSRole), &sourceNSRole)).To(Succeed()) + Expect(sourceNSRole.Rules).To(Equal( + []rbacv1.PolicyRule{{ + APIGroups: []string{"*"}, + Resources: []string{"*"}, + Verbs: []string{"*"}, + }}, + )) + + sourceNSRoleBinding := rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{Name: "source-ns-openshift-gitops-argocd-application-controller", Namespace: sourceNS.Name}, + } + Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(&sourceNSRoleBinding), &sourceNSRoleBinding)).To(Succeed()) + Expect(sourceNSRoleBinding.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "source-ns-openshift-gitops-argocd-application-controller", + })) + Expect(sourceNSRoleBinding.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", Name: "argocd-argocd-application-controller"}})) + + By("creating Argo CD Application which tries to deploy from source-ns instance to target-ns NS") + app := &argocdv1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "nginx", Namespace: sourceNS.Name}, + Spec: argocdv1alpha1.ApplicationSpec{ + Source: &argocdv1alpha1.ApplicationSource{ + Path: "test/examples/nginx", + RepoURL: "https://github.com/jgwest/gitops-operator", + TargetRevision: "HEAD", + }, + Destination: argocdv1alpha1.ApplicationDestination{ + Namespace: targetNS.Name, + Server: "https://kubernetes.default.svc", + }, + Project: "default", + SyncPolicy: &argocdv1alpha1.SyncPolicy{ + Automated: &argocdv1alpha1.SyncPolicyAutomated{}, + }, + }, + } + Expect(k8sClient.Create(ctx, app)).To(Succeed()) + + By("verifying Argo CD in source-ns is able to deploy to managed namespace target-ns") + Eventually(app, "60s", "5s").Should(applicationFixture.HaveHealthStatusCode(health.HealthStatusHealthy)) + Eventually(app, "60s", "5s").Should(applicationFixture.HaveSyncStatusCode(argocdv1alpha1.SyncStatusCodeSynced)) + + }) + + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-020_validate_redis_ha_nonha_test.go b/test/openshift/e2e/ginkgo/sequential/1-020_validate_redis_ha_nonha_test.go new file mode 100644 index 000000000..e89859c79 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-020_validate_redis_ha_nonha_test.go @@ -0,0 +1,197 @@ +/* +Copyright 2021. + +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 sequential + +import ( + "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/node" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-020_validate_redis_ha_nonha", func() { + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + }) + + It("validates Redis HA and Non-HA", func() { + + // This test enables HA, so it needs to be running on a cluster with at least 3 nodes + node.ExpectHasAtLeastXNodes(3) + + By("ensuring the openshift-gitops Argo CD instance is running") + gitopsArgoCD, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(gitopsArgoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(gitopsArgoCD).Should(argocdFixture.HaveRedisStatus("Running")) + + By("verifying various expected resources exist in namespace") + Eventually(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis", Namespace: "openshift-gitops"}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deploymentFixture.HaveReadyReplicas(1)) + + By("verifies Redis HA resources should not exist since we are in non-HA mode") + + Consistently(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Consistently(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-haproxy", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Consistently(&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-haproxy", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Consistently(&appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-server", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + By("enabling HA on openshift-gitops Argo CD instance") + argocdFixture.Update(gitopsArgoCD, func(argocd *v1beta1.ArgoCD) { + argocd.Spec.HA.Enabled = true + }) + + By("verifying expected HA resources are eventually created after we enabled HA") + + Eventually(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-haproxy", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(gitopsArgoCD, "4m", "5s").Should(argocdFixture.HavePhase("Available")) + Eventually(gitopsArgoCD).Should(argocdFixture.HaveRedisStatus("Running")) + + statefulSet := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-server", Namespace: "openshift-gitops"}} + Eventually(statefulSet).Should(statefulsetFixture.HaveReadyReplicas(3)) + Expect(statefulSet.Spec.Template.Spec.Affinity).To(Equal( + &corev1.Affinity{ + PodAntiAffinity: &corev1.PodAntiAffinity{ + RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{ + { + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/name": "openshift-gitops-redis-ha", + }, + }, + TopologyKey: "kubernetes.io/hostname", + }, + }, + }, + })) + + Eventually(&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-haproxy", Namespace: "openshift-gitops"}}, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + + By("verifying non-HA resources no longer exist, since HA is enabled") + + Expect(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis", Namespace: "openshift-gitops"}}).To(k8sFixture.NotExistByName()) + + Expect(&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis", Namespace: "openshift-gitops"}}).To(k8sFixture.NotExistByName()) + + By("updating ArgoCD CR to add cpu and memory resource request and limits to HA workloads") + + argocdFixture.Update(gitopsArgoCD, func(argocd *v1beta1.ArgoCD) { + argocd.Spec.HA.Enabled = true + argocd.Spec.HA.Resources = &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("256Mi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("200m"), + corev1.ResourceMemory: resource.MustParse("128Mi"), + }, + } + }) + + By("Argo CD should eventually be ready after updating the resource requirements") + Eventually(gitopsArgoCD, "5m", "5s").Should(argocdFixture.BeAvailable()) // it can take a while to schedule the Pods + Eventually(gitopsArgoCD, "60s", "5s").Should(argocdFixture.HaveRedisStatus("Running")) + + By("verifying Deployment and StatefulSet have expected resources that we set in previous step") + + depl = &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-haproxy", Namespace: "openshift-gitops"}} + Eventually(depl, "2m", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + + haProxyContainer := deploymentFixture.GetTemplateSpecContainerByName("haproxy", *depl) + + Expect(haProxyContainer).ToNot(BeNil()) + Expect(haProxyContainer.Resources.Limits.Cpu().AsDec().String()).To(Equal("0.500")) + Expect(haProxyContainer.Resources.Limits.Memory().AsDec().String()).To(Equal("268435456")) // 256Mib in bytes + Expect(haProxyContainer.Resources.Requests.Cpu().AsDec().String()).To(Equal("0.200")) + Expect(haProxyContainer.Resources.Requests.Memory().AsDec().String()).To(Equal("134217728")) // 128MiB in bytes + + configInitContainer := deploymentFixture.GetTemplateSpecInitContainerByName("config-init", *depl) + + Expect(configInitContainer.Resources.Limits.Cpu().AsDec().String()).To(Equal("0.500")) + Expect(configInitContainer.Resources.Limits.Memory().AsDec().String()).To(Equal("268435456")) + Expect(configInitContainer.Resources.Requests.Cpu().AsDec().String()).To(Equal("0.200")) + Expect(configInitContainer.Resources.Requests.Memory().AsDec().String()).To(Equal("134217728")) + + ss := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-server", Namespace: "openshift-gitops"}} + Eventually(ss, "2m", "5s").Should(statefulsetFixture.HaveReadyReplicas(3)) + + redisContainer := statefulsetFixture.GetTemplateSpecContainerByName("redis", *ss) + Expect(redisContainer).ToNot(BeNil()) + Expect(redisContainer.Resources.Limits.Cpu().AsDec().String()).To(Equal("0.500")) + Expect(redisContainer.Resources.Limits.Memory().AsDec().String()).To(Equal("268435456")) + Expect(redisContainer.Resources.Requests.Cpu().AsDec().String()).To(Equal("0.200")) + Expect(redisContainer.Resources.Requests.Memory().AsDec().String()).To(Equal("134217728")) + + sentinelContainer := statefulsetFixture.GetTemplateSpecContainerByName("sentinel", *ss) + Expect(sentinelContainer).ToNot(BeNil()) + Expect(sentinelContainer.Resources.Limits.Cpu().AsDec().String()).To(Equal("0.500")) + Expect(sentinelContainer.Resources.Limits.Memory().AsDec().String()).To(Equal("268435456")) + Expect(sentinelContainer.Resources.Requests.Cpu().AsDec().String()).To(Equal("0.200")) + Expect(sentinelContainer.Resources.Requests.Memory().AsDec().String()).To(Equal("134217728")) + + configInitContainer = statefulsetFixture.GetTemplateSpecInitContainerByName("config-init", *ss) + Expect(configInitContainer.Resources.Limits.Cpu().AsDec().String()).To(Equal("0.500")) + Expect(configInitContainer.Resources.Limits.Memory().AsDec().String()).To(Equal("268435456")) + Expect(configInitContainer.Resources.Requests.Cpu().AsDec().String()).To(Equal("0.200")) + Expect(configInitContainer.Resources.Requests.Memory().AsDec().String()).To(Equal("134217728")) + + By("disabling HA on ArgoCD CR") + + argocdFixture.Update(gitopsArgoCD, func(argocd *v1beta1.ArgoCD) { + argocd.Spec.HA.Enabled = false + }) + + By("verifying Argo CD becomes ready again after HA is disabled") + + Eventually(gitopsArgoCD, "60s", "5s").Should(argocdFixture.BeAvailable()) + Eventually(gitopsArgoCD, "60s", "5s").Should(argocdFixture.HaveRedisStatus("Running")) + + By("verifying expected non-HA resources exist again and HA resources no longer exist") + depl = &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis", Namespace: "openshift-gitops"}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl).Should(deploymentFixture.HaveReadyReplicas(1)) + + Consistently(&appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-haproxy", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Consistently(&appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis-ha-server", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-026-validate_backend_service_permissions_test.go b/test/openshift/e2e/ginkgo/sequential/1-026-validate_backend_service_permissions_test.go new file mode 100644 index 000000000..5e21496e7 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-026-validate_backend_service_permissions_test.go @@ -0,0 +1,63 @@ +package sequential + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-026-validate_backend_service_permissions", func() { + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + }) + + It("validates backend service permissions", func() { + + By("verifying that various backend-related resources exist and have the expected values") + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Expect(depl.Spec.Template.Spec.ServiceAccountName).To(Equal("gitops-service-cluster")) + Expect(depl.Spec.Template.Spec.DeprecatedServiceAccount).To(Equal("gitops-service-cluster")) + + Eventually(&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "gitops-service-cluster", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + cr := &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "gitops-service-cluster"}} + Eventually(cr).Should(k8sFixture.ExistByName()) + Expect(cr.Rules).To(Equal([]rbacv1.PolicyRule{ + { + APIGroups: []string{"argoproj.io"}, + Resources: []string{"applications"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets"}, + Verbs: []string{"get", "list", "watch"}, + }, + })) + + crb := &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "gitops-service-cluster"}} + Eventually(crb).Should(k8sFixture.ExistByName()) + Expect(crb.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "gitops-service-cluster", + })) + Expect(crb.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: "gitops-service-cluster", + Namespace: "openshift-gitops"}, + })) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-028-validate_run_on_infra_test.go b/test/openshift/e2e/ginkgo/sequential/1-028-validate_run_on_infra_test.go new file mode 100644 index 000000000..721b36f07 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-028-validate_run_on_infra_test.go @@ -0,0 +1,221 @@ +package sequential + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-028-validate_run_on_infra_test", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates that Argo CD runs on infra nodes", func() { + + By("enabling run on infra on GitOpsService CR") + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + } + Expect(gitopsService).To(k8sFixture.ExistByName()) + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.RunOnInfra = true + gs.Spec.Tolerations = []corev1.Toleration{{Effect: "NoSchedule", Key: "infra", Value: "reserved"}} + }) + + // Ensure the change is reverted when the test exits + defer func() { + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.RunOnInfra = false + gs.Spec.Tolerations = nil + }) + }() + + By("verifying the openshift-gitops resources have the run on infra labels and tolerations applied") + clusterDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}} + Eventually(clusterDepl).Should( + And( + deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + }), + deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}}), + )) + + serverDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-server", Namespace: "openshift-gitops"}} + Eventually(serverDepl).Should( + And( + deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + }), + deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}}), + )) + + repoServerDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-repo-server", Namespace: "openshift-gitops"}} + Eventually(repoServerDepl).Should( + And( + deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + }), + deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}}), + )) + + dexServerDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-dex-server", Namespace: "openshift-gitops"}} + Eventually(dexServerDepl).Should( + And( + deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + }), + deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}}), + )) + + redisServerDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-redis", Namespace: "openshift-gitops"}} + Eventually(redisServerDepl).Should( + And( + deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + }), + deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}}), + )) + + appControllerSS := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-application-controller", Namespace: "openshift-gitops"}} + Eventually(appControllerSS).Should( + And( + statefulsetFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + }), + statefulsetFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}}), + )) + + By("creating a simple namespace-scoped Argo CD instance in another namespace") + + randomNamespace := fixture.CreateRandomE2ETestNamespace() + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: randomNamespace.Name}, + Spec: argov1beta1api.ArgoCDSpec{}, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + Eventually(argoCD, "90s", "5s").Should(argocdFixture.HavePhase("Available")) + + // verifyNotPresentInNamespace verifies that the various Argo CD resources in the namespace do not have 'run on infra' set + verifyNotPresentInNamespace := func(ns string) { + + serverDepl = &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-server", Namespace: ns}} + Eventually(serverDepl).ShouldNot(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + })) + Eventually(serverDepl).ShouldNot(deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}})) + + repoServer := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-repo-server", Namespace: ns}} + Eventually(repoServer).ShouldNot(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + })) + Eventually(repoServer).ShouldNot(deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}})) + + dexServer := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-dex-server", Namespace: ns}} + Eventually(dexServer).ShouldNot(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + })) + Eventually(dexServer).ShouldNot(deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}})) + + redisDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-redis", Namespace: ns}} + Eventually(redisDepl).ShouldNot(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + })) + Eventually(redisDepl).ShouldNot(deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}})) + + appControllerSS = &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "argocd-application-controller", Namespace: ns}} + Eventually(appControllerSS).ShouldNot(statefulsetFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + })) + Eventually(appControllerSS).ShouldNot(statefulsetFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}})) + + } + + By("verifying that the namespace-scoped Argo CD instance does NOT have run on infra set.") + verifyNotPresentInNamespace(randomNamespace.Name) + // Run on infra should only be set on openshift-gitops + + By("disabling run on infra on GitOpsService CR") + + gitopsService = &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + } + Expect(gitopsService).To(k8sFixture.ExistByName()) + + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.RunOnInfra = false + gs.Spec.Tolerations = nil + }) + + By("verifying that the resources in openshift-gitops no longer have run on infra tolerations/label set") + + clusterDepl = &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "cluster", Namespace: "openshift-gitops"}} + Eventually(serverDepl).ShouldNot(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "node-role.kubernetes.io/infra": "", + "kubernetes.io/os": "linux", + })) + + Eventually(serverDepl).ShouldNot(deploymentFixture.HaveTolerations([]corev1.Toleration{ + {Key: "infra", Effect: "NoSchedule", Value: "reserved"}}), + ) + + verifyNotPresentInNamespace("openshift-gitops") + + // This is required, otherwise StatefulSet will be stuck for every subsequent test. This was ported from kuttl (but we delete the SS rather than updating its replicas) + appControllerSS = &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-application-controller", Namespace: "openshift-gitops"}} + + Expect(k8sClient.Delete(ctx, appControllerSS)).To(Succeed()) + Eventually(appControllerSS).Should(k8sFixture.ExistByName()) + + Eventually(appControllerSS, "2m", "5s").Should(statefulsetFixture.HaveReadyReplicas(1)) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-034_validate_custom_roles_test.go b/test/openshift/e2e/ginkgo/sequential/1-034_validate_custom_roles_test.go new file mode 100644 index 000000000..1cd2496db --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-034_validate_custom_roles_test.go @@ -0,0 +1,189 @@ +package sequential + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-034-validate_custom_roles", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("validates CONTROLLER_CLUSTER_ROLE and SERVER_CLUSTER_ROLE env var supports namespace-scoped instances, and that the default roles are removed", func() { + + if fixture.EnvLocalRun() { + Skip("Skipping test as LOCAL_RUN env var is set. In this case, it is not possible to set env var on gitops operator controller process.") + return + } + + By("creating custom Argo CD Namespace test-1-034-custom") + test1NS := fixture.CreateNamespace("test-1-034-custom") + + By("creating a test namespace with managed-by label, managed by test1 ns") + customRoleNS := fixture.CreateManagedNamespace("custom-role-namespace", test1NS.Name) + + By("creating a sample cluster role for application-controller and server") + clusterRole := &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "custom-argocd-role", + }, + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"list", "watch", "get"}, + APIGroups: []string{"*"}, + Resources: []string{"*"}, + }, + }, + } + Expect(k8sClient.Create(ctx, clusterRole)).To(Succeed()) + + By("creating an Argo CD instance in the new namespace") + argoCDInTest1NS := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: test1NS.Name}, + } + Expect(k8sClient.Create(ctx, argoCDInTest1NS)).To(Succeed()) + + Eventually(argoCDInTest1NS, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("checking the default managed-by roles are created in the managed namespace") + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: customRoleNS.Name}}).Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: customRoleNS.Name}}).Should(k8sFixture.ExistByName()) + + rb := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: customRoleNS.Name}} + Eventually(rb).Should(k8sFixture.ExistByName()) + Expect(rb.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "argocd-argocd-server", + })) + Expect(rb.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: "argocd-argocd-server", + Namespace: test1NS.Name, + }})) + + rb = &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: customRoleNS.Name}} + Eventually(rb).Should(k8sFixture.ExistByName()) + Expect(rb.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: "argocd-argocd-application-controller", + })) + Expect(rb.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: "argocd-argocd-application-controller", + Namespace: test1NS.Name, + }})) + + By("adding custom CONTROLLER and SERVER cluster roles to Subscription or operator Deployment") + + fixture.SetEnvInOperatorSubscriptionOrDeployment("CONTROLLER_CLUSTER_ROLE", "custom-argocd-role") + fixture.SetEnvInOperatorSubscriptionOrDeployment("SERVER_CLUSTER_ROLE", "custom-argocd-role") + + defer func() { + By("cleaning up changes to the Subscription or operator Deployment") + Expect(fixture.RestoreSubcriptionToDefault()).To(Succeed()) + }() + + By("checking if the default roles are removed from the namespace") + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: customRoleNS.Name}}, "120s", "1s").Should(k8sFixture.NotExistByName()) + Consistently(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: customRoleNS.Name}}).Should(k8sFixture.NotExistByName()) + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: customRoleNS.Name}}).Should(k8sFixture.NotExistByName()) + Consistently(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: customRoleNS.Name}}).Should(k8sFixture.NotExistByName()) + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: test1NS.Name}}).Should(k8sFixture.NotExistByName()) + Consistently(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: test1NS.Name}}).Should(k8sFixture.NotExistByName()) + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: test1NS.Name}}).Should(k8sFixture.NotExistByName()) + Consistently(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: test1NS.Name}}).Should(k8sFixture.NotExistByName()) + + By("checking if the Rolebindings are updated in all the namespaces") + + rb = &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: customRoleNS.Name}} + Eventually(rb).Should(k8sFixture.ExistByName()) + Expect(rb.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "custom-argocd-role", + })) + Expect(rb.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: "argocd-argocd-server", + Namespace: test1NS.Name, + }})) + + rb = &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: customRoleNS.Name}} + Eventually(rb).Should(k8sFixture.ExistByName()) + Expect(rb.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "custom-argocd-role", + })) + Expect(rb.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: "argocd-argocd-application-controller", + Namespace: test1NS.Name, + }})) + + rb = &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-server", Namespace: test1NS.Name}} + Eventually(rb).Should(k8sFixture.ExistByName()) + Expect(rb.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "custom-argocd-role", + })) + Expect(rb.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: "argocd-argocd-server", + Namespace: test1NS.Name, + }})) + + rb = &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-application-controller", Namespace: test1NS.Name}} + Eventually(rb).Should(k8sFixture.ExistByName()) + Expect(rb.RoleRef).To(Equal(rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: "custom-argocd-role", + })) + Expect(rb.Subjects).To(Equal([]rbacv1.Subject{{ + Kind: "ServiceAccount", + Name: "argocd-argocd-application-controller", + Namespace: test1NS.Name, + }})) + + By("deleting namespaces created by the test") + + Expect(k8sClient.Delete(ctx, argoCDInTest1NS)).To(Succeed()) + Expect(k8sClient.Delete(ctx, &test1NS)).To(Succeed()) + Expect(k8sClient.Delete(ctx, &customRoleNS)).To(Succeed()) + Expect(k8sClient.Delete(ctx, &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "custom-argocd-role"}})).To(Succeed()) + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-035_validate_argocd_secret_repopulate_test.go b/test/openshift/e2e/ginkgo/sequential/1-035_validate_argocd_secret_repopulate_test.go new file mode 100644 index 000000000..4069f100d --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-035_validate_argocd_secret_repopulate_test.go @@ -0,0 +1,83 @@ +package sequential + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + secretFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/secret" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-035-validate_argocd_secret_repopulate", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies 'argocd-secret' secret is regenerated and we are able to login using that Secret", func() { + + By("checking OpenShift GitOps ArgoCD instance is available") + argocd, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(argocd, "4m", "5s").Should(argocdFixture.BeAvailable()) + + By("removing data from argocd-secret, to check that it is regenerated") + secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "argocd-secret", Namespace: "openshift-gitops"}} + secretFixture.Update(secret, func(s *corev1.Secret) { + s.Data = nil + }) + + By("verifying that Secret repopulates") + Eventually(func() bool { + err := k8sClient.Get(ctx, client.ObjectKeyFromObject(secret), secret) + if err != nil { + GinkgoWriter.Println(err) + return false + } + + if len(secret.Data) == 0 { + return false + } + + return true + }).Should(BeTrue()) + + Eventually(argocd, "4m", "5s").Should(argocdFixture.BeAvailable()) + + if !fixture.EnvLocalRun() { + + // Skip verifying operator deployment when we are running the operator locally + By("verifying operator Deployment is ready") + + depl := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "openshift-gitops-operator-controller-manager", + Namespace: "openshift-gitops-operator", + }, + } + Eventually(depl, "1m", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + } + + Expect(argocdFixture.LogInToDefaultArgoCDInstance()).To(Succeed()) + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-040_validate_quoted_RBAC_group_names_test.go b/test/openshift/e2e/ginkgo/sequential/1-040_validate_quoted_RBAC_group_names_test.go new file mode 100644 index 000000000..507d12fea --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-040_validate_quoted_RBAC_group_names_test.go @@ -0,0 +1,46 @@ +package sequential + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-040-validate_quoted_RBAC_group_names", func() { + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + }) + + It("creates a project role 'somerole' and group claim, and verifies group claim contains the expected data", func() { + + By("logging in to Argo CD instance") + Expect(argocdFixture.LogInToDefaultArgoCDInstance()).To(Succeed()) + + By("Creating a new 'somerole' role in default project") + output, err := argocdFixture.RunArgoCDCLI("proj", "role", "create", "default", "somerole") + Expect(err).ToNot(HaveOccurred()) + + // Delete the new role we created during the test + defer func() { + By("deleting the role we created during the test") + _, err = argocdFixture.RunArgoCDCLI("proj", "role", "delete", "default", "somerole") + Expect(err).ToNot(HaveOccurred()) + }() + + Expect(output).To(ContainSubstring("Role 'somerole' created")) + + By("adding a group claim to the somerole role") + output, err = argocdFixture.RunArgoCDCLI("proj", "role", "add-group", "default", "somerole", "\"CN=foo,OU=bar,O=baz\"") + Expect(err).ToNot(HaveOccurred()) + + Expect(output).To(ContainSubstring("added to role 'somerole'")) + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-041_TODO_validate_argocd_sync_alert_test.go b/test/openshift/e2e/ginkgo/sequential/1-041_TODO_validate_argocd_sync_alert_test.go new file mode 100644 index 000000000..83803ae52 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-041_TODO_validate_argocd_sync_alert_test.go @@ -0,0 +1,59 @@ +package sequential + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-041_validate_argocd_sync_alert", func() { + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + + }) + + It("PORTING TEST IS BLOCKED DUE TO COREOS DEPENDENCY", func() { + + By("checking OpenShift GitOps ArgoCD instance is available") + + argocd, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(argocd, "3m", "5s").Should(argocdFixture.BeAvailable()) + + // --- + // apiVersion: monitoring.coreos.com/v1 + // kind: PrometheusRule + // metadata: + // name: gitops-operator-argocd-alerts + // namespace: openshift-gitops + // spec: + // groups: + // - name: GitOpsOperatorArgoCD + // rules: + // - alert: ArgoCDSyncAlert + // annotations: + // summary: Argo CD application is out of sync + // description: Argo CD application {{ $labels.name }} is out of sync. Check ArgoCDSyncAlert status, this alert is designed to notify that an application managed by Argo CD is out of sync. + // expr: argocd_app_info{namespace="openshift-gitops",sync_status="OutOfSync"} > 0 + // for: 5m + // labels: + // severity: warning + + // promRule := monitoringv1.PrometheusRule{ + // ObjectMeta: metav1.ObjectMeta{ + // Name: "gitops-operator-argocd-alerts", + // Namespace: "openshift-gitops", + // }, + // Spec: monitoringv1.PrometheusRuleSpec{ + // Groups: []monitoringv1.RuleGroup{}, + // }, + // } + + }) + }) +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-050_validate_sso_test.go b/test/openshift/e2e/ginkgo/sequential/1-050_validate_sso_test.go new file mode 100644 index 000000000..9b701ec2f --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-050_validate_sso_test.go @@ -0,0 +1,143 @@ +package sequential + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + osappsv1 "github.com/openshift/api/apps/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-050_validate_sso", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures Dex/Keycloak SSO can be enabled and disabled on a namespace-scoped Argo CD instance", func() { + + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + By("creating a new Argo CD instance with dex and openshift oauth enabled") + + newArgoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd", + Namespace: ns.Name, + }, + Spec: argov1beta1api.ArgoCDSpec{ + SSO: &argov1beta1api.ArgoCDSSOSpec{ + Provider: "dex", + Dex: &argov1beta1api.ArgoCDDexSpec{ + OpenShiftOAuth: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, newArgoCD)).To(Succeed()) + + By("verifying Argo CD is available and Dex is running") + + Eventually(newArgoCD, "3m", "5s").Should( + SatisfyAll(argocdFixture.BeAvailable(), argocdFixture.HaveSSOStatus("Running"))) + + dexDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argocd-dex-server", Namespace: ns.Name}} + Eventually(dexDepl).Should(k8sFixture.ExistByName()) + Eventually(dexDepl).Should(deploymentFixture.HaveReadyReplicas(1)) + + sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-dex-server", Namespace: ns.Name}} + Eventually(sa).Should(k8sFixture.ExistByName()) + + rb := &rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-dex-server", Namespace: ns.Name}} + Eventually(rb).Should(k8sFixture.ExistByName()) + + r := &rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "argocd-argocd-dex-server", Namespace: ns.Name}} + Eventually(r).Should(k8sFixture.ExistByName()) + + service := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "argocd-dex-server", Namespace: ns.Name}} + Eventually(service).Should(k8sFixture.ExistByName()) + + By("disabling SSO") + + argocdFixture.Update(newArgoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.SSO = nil + }) + + By("verifying that Argo CD becomes available after disabling SSO, and SSO is disabled") + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.HaveSSOStatus("Unknown")) + + By("verifying dex resources no longer exist") + Eventually(dexDepl).Should(k8sFixture.NotExistByName()) + Consistently(dexDepl).Should(k8sFixture.NotExistByName()) + + Eventually(sa).Should(k8sFixture.NotExistByName()) + Consistently(sa).Should(k8sFixture.NotExistByName()) + + Eventually(rb).Should(k8sFixture.NotExistByName()) + Consistently(rb).Should(k8sFixture.NotExistByName()) + + Eventually(r).Should(k8sFixture.NotExistByName()) + Consistently(r).Should(k8sFixture.NotExistByName()) + + Eventually(service).Should(k8sFixture.NotExistByName()) + Consistently(service).Should(k8sFixture.NotExistByName()) + + By("switching ArgoCD to SSO enabled via keycloak") + argocdFixture.Update(newArgoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.SSO = &argov1beta1api.ArgoCDSSOSpec{ + Provider: "keycloak", + Dex: &argov1beta1api.ArgoCDDexSpec{ + Config: "test", + }, + } + }) + + By("verifying that with keycloak, Argo CD becomes available but SSO is failed") + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.HaveSSOStatus("Failed")) + By("verifying keycloak DeploymentConfigs are not used") + + Eventually(&osappsv1.DeploymentConfig{ObjectMeta: metav1.ObjectMeta{Name: "keycloak", Namespace: ns.Name}}). + Should(k8sFixture.NotExistByName()) + Consistently(&osappsv1.DeploymentConfig{ObjectMeta: metav1.ObjectMeta{Name: "keycloak", Namespace: ns.Name}}). + Should(k8sFixture.NotExistByName()) + + By("patching the CR to remove dex entry from .spec.sso") + argocdFixture.Update(newArgoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.SSO.Dex = nil + }) + + By("verifying keycloak is now used") + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(newArgoCD, "3m", "5s").Should(argocdFixture.HaveSSOStatus("Running")) + + Eventually(&osappsv1.DeploymentConfig{ObjectMeta: metav1.ObjectMeta{Name: "keycloak", Namespace: ns.Name}}). + Should(k8sFixture.ExistByName()) + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-056_validate_managed-by_test.go b/test/openshift/e2e/ginkgo/sequential/1-056_validate_managed-by_test.go new file mode 100644 index 000000000..e0b17d18a --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-056_validate_managed-by_test.go @@ -0,0 +1,160 @@ +package sequential + +import ( + "context" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-056_validate_managed-by", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that managed-by works as expected and that REMOVE_MANAGED_BY_LABEL_ON_ARGOCD_DELETION will remove managed-by label when the related ArgoCD instance is deleted", func() { + + By("creating two namespaces in managed-by relationship") + + test156TargetNS := fixture.CreateNamespace("test-1-56-target") + test156CustomNS := fixture.CreateManagedNamespace("test-1-56-custom", test156TargetNS.Name) + + By("creating simple Argo CD instance in test-1-56-target NS") + argoCD_test156Target := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd", Namespace: "test-1-56-target"}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD_test156Target)).To(Succeed()) + + By("verifying Argo CD instance is started and expected resources exist") + Eventually(argoCD_test156Target, "3m", "5s").Should(argocdFixture.BeAvailable()) + + redisDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-redis", Namespace: test156TargetNS.Name}} + Eventually(redisDepl, "60s", "5s").Should( + And( + deploymentFixture.HaveReadyReplicas(1), + deploymentFixture.HaveReplicas(1))) + + repoDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-repo-server", Namespace: test156TargetNS.Name}} + Eventually(repoDepl, "60s", "5s").Should( + And( + deploymentFixture.HaveReadyReplicas(1), + deploymentFixture.HaveReplicas(1))) + + serverDepl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-server", Namespace: test156TargetNS.Name}} + Eventually(serverDepl, "60s", "5s").Should( + And( + deploymentFixture.HaveReadyReplicas(1), + deploymentFixture.HaveReplicas(1))) + + appControllerSS := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-application-controller", Namespace: test156TargetNS.Name}} + Eventually(appControllerSS, "60s", "5s").Should( + And( + statefulsetFixture.HaveReadyReplicas(1), + statefulsetFixture.HaveReplicas(1))) + + By("deleting Argo CD instance in test-1-56-target") + Expect(k8sClient.Delete(ctx, argoCD_test156Target)).To(Succeed()) + + By("verifying test-1-56-custom is managed by test-1-56-target") + + Eventually(&test156CustomNS).Should(k8sFixture.HaveLabelWithValue("argocd.argoproj.io/managed-by", "test-1-56-target")) + + if !fixture.EnvLocalRun() { + + By("adding REMOVE_MANAGED_BY_LABEL_ON_ARGOCD_DELETION=true to operator Subscription or Deployment") + + fixture.SetEnvInOperatorSubscriptionOrDeployment("REMOVE_MANAGED_BY_LABEL_ON_ARGOCD_DELETION", "true") + + By("creating new 2 new namespaces in managed-by relationship and an Argo CD instance to manage them") + + test156Target2NS := fixture.CreateNamespace("test-1-56-target-2") + test156Custom2NS := fixture.CreateManagedNamespace("test-1-56-custom-2", test156Target2NS.Name) + + argoCD_test156Target2 := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-2", Namespace: "test-1-56-target-2"}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD_test156Target2)).To(Succeed()) + + By("verifying new Argo CD is available along with the expected resources, in the new Namespace") + Eventually(argoCD_test156Target2, "3m", "5s").Should(argocdFixture.BeAvailable()) + + redisDepl2 := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-2-redis", Namespace: test156Target2NS.Name}} + Eventually(redisDepl2, "60s", "5s").Should( + And( + deploymentFixture.HaveReadyReplicas(1), + deploymentFixture.HaveReplicas(1))) + + repoDepl2 := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-2-repo-server", Namespace: test156Target2NS.Name}} + Eventually(repoDepl2, "60s", "5s").Should( + And( + deploymentFixture.HaveReadyReplicas(1), + deploymentFixture.HaveReplicas(1))) + + serverDepl2 := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-2-server", Namespace: test156Target2NS.Name}} + Eventually(serverDepl2, "60s", "5s").Should( + And( + deploymentFixture.HaveReadyReplicas(1), + deploymentFixture.HaveReplicas(1))) + + appControllerSS2 := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "example-argocd-2-application-controller", Namespace: test156Target2NS.Name}} + Eventually(appControllerSS2, "60s", "5s").Should( + And( + statefulsetFixture.HaveReadyReplicas(1), + statefulsetFixture.HaveReplicas(1))) + + By("deleting the Argo CD in new namespace") + Expect(k8sClient.Delete(ctx, argoCD_test156Target2)).To(Succeed()) + + By("verifying Namespace test-1-56-custom-2 does not have managed-by label for deleted Argo CD namespace") + Eventually(&test156Custom2NS, "60s", "5s").Should(k8sFixture.NotHaveLabelWithValue("argocd.argoproj.io/managed-by", "test-1-56-target-2")) + + By("removing REMOVE_MANAGED_BY_LABEL_ON_ARGOCD_DELETION from operator Subscription or Deplyoment") + Expect(fixture.RemoveEnvFromOperatorSubscriptionOrDeployment("REMOVE_MANAGED_BY_LABEL_ON_ARGOCD_DELETION")).To(Succeed()) + + By("removing Namespaces created during the test") + Expect(k8sClient.Delete(ctx, &test156Custom2NS)).To(Succeed()) + Expect(k8sClient.Delete(ctx, &test156Target2NS)).To(Succeed()) + } + + Expect(k8sClient.Delete(ctx, &test156CustomNS)).To(Succeed()) + Expect(k8sClient.Delete(ctx, &test156TargetNS)).To(Succeed()) + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-071_validate_node_selectors_test.go b/test/openshift/e2e/ginkgo/sequential/1-071_validate_node_selectors_test.go new file mode 100644 index 000000000..beb189fef --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-071_validate_node_selectors_test.go @@ -0,0 +1,165 @@ +package sequential + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + gitopsoperatorv1alpha1 "github.com/redhat-developer/gitops-operator/api/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + gitopsserviceFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/gitopsservice" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-071_validate_node_selectors", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies changes to GitOpsService's nodeselector, tolerations, and runOnInfra will modify Argo CD Deployments and StatefulSets", func() { + + By("ensuring Deployments and StatefulSets have nodeSelector of 'kubernetes.io/os: linux'") + + deploymentNameList := []string{"cluster", "openshift-gitops-server", "openshift-gitops-repo-server", "openshift-gitops-dex-server", "openshift-gitops-redis"} + + for _, deploymentName := range deploymentNameList { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deploymentName, Namespace: "openshift-gitops"}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Expect(depl.Spec.Template.Spec.NodeSelector).Should(Equal(map[string]string{"kubernetes.io/os": "linux"})) + } + + appControllerSS := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-application-controller", Namespace: "openshift-gitops"}} + Eventually(appControllerSS).Should(k8sFixture.ExistByName()) + Expect(appControllerSS.Spec.Template.Spec.NodeSelector).Should(Equal(map[string]string{"kubernetes.io/os": "linux"})) + + By("adding 'nodeSelector: {key1: value1}' to GitOpsService CR") + + gitopsService := &gitopsoperatorv1alpha1.GitopsService{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + } + Expect(gitopsService).To(k8sFixture.ExistByName()) + + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + if gs.Spec.NodeSelector == nil { + gs.Spec.NodeSelector = map[string]string{} + } + + gs.Spec.NodeSelector["key1"] = "value1" + }) + + By("ensuring Deployments and StatefulSets pick up the change we made to nodeSelector in GitOpsService CR") + + for _, deploymentName := range deploymentNameList { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deploymentName, Namespace: "openshift-gitops"}} + Eventually(depl).Should(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "kubernetes.io/os": "linux", + "key1": "value1", + })) + } + + Eventually(appControllerSS).Should(statefulsetFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "kubernetes.io/os": "linux", + "key1": "value1", + })) + + By("enabling runOnInfra and setting various tolerations on GitOpsService") + + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.RunOnInfra = true + gs.Spec.Tolerations = []corev1.Toleration{{ + Effect: "NoSchedule", + Key: "infra", + Value: "reserved"}} + }) + + By("ensuring Deployments and StatefulSets pick up the change to nodeSelector and tolerations") + + for _, deploymentName := range deploymentNameList { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deploymentName, Namespace: "openshift-gitops"}} + Eventually(depl).Should(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "kubernetes.io/os": "linux", + "key1": "value1", + "node-role.kubernetes.io/infra": "", + })) + Eventually(depl).Should(deploymentFixture.HaveTolerations([]corev1.Toleration{{ + Effect: "NoSchedule", + Key: "infra", + Value: "reserved", + }})) + } + + Eventually(appControllerSS).Should(statefulsetFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "kubernetes.io/os": "linux", + "key1": "value1", + "node-role.kubernetes.io/infra": "", + })) + Eventually(appControllerSS).Should(statefulsetFixture.HaveTolerations([]corev1.Toleration{{ + Effect: "NoSchedule", + Key: "infra", + Value: "reserved", + }})) + + By("removing all our previous changes from GitOpsService") + + gitopsserviceFixture.Update(gitopsService, func(gs *gitopsoperatorv1alpha1.GitopsService) { + gs.Spec.RunOnInfra = false + gs.Spec.Tolerations = nil + gs.Spec.NodeSelector = nil + }) + + By("ensuring Deployments and StatefulSets have the nodeSelector and tolerations removed") + + for _, deploymentName := range deploymentNameList { + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: deploymentName, Namespace: "openshift-gitops"}} + Eventually(depl).ShouldNot(deploymentFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "kubernetes.io/os": "linux", + "key1": "value1", + "node-role.kubernetes.io/infra": "", + })) + Eventually(depl).ShouldNot(deploymentFixture.HaveTolerations([]corev1.Toleration{{ + Effect: "NoSchedule", + Key: "infra", + Value: "reserved", + }})) + } + + Eventually(appControllerSS).ShouldNot(statefulsetFixture.HaveTemplateSpecNodeSelector(map[string]string{ + "kubernetes.io/os": "linux", + "key1": "value1", + "node-role.kubernetes.io/infra": "", + })) + Eventually(appControllerSS).ShouldNot(statefulsetFixture.HaveTolerations([]corev1.Toleration{{ + Effect: "NoSchedule", + Key: "infra", + Value: "reserved", + }})) + + // This is required, otherwise StatefulSet will be stuck for every subsequent test. This was ported from kuttl (but we delete the SS rather than updating its replicas, which is what kuttl did) + Expect(k8sClient.Delete(ctx, appControllerSS)).To(Succeed()) + Eventually(appControllerSS).Should(k8sFixture.ExistByName()) + + Eventually(appControllerSS, "2m", "5s").Should(statefulsetFixture.HaveReadyReplicas(1)) + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-078_validate_default_argocd_consoleLink_test.go b/test/openshift/e2e/ginkgo/sequential/1-078_validate_default_argocd_consoleLink_test.go new file mode 100644 index 000000000..6e3834b05 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-078_validate_default_argocd_consoleLink_test.go @@ -0,0 +1,113 @@ +package sequential + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + consolev1 "github.com/openshift/api/console/v1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-078_validate_default_argocd_consoleLink", func() { + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + }) + + It("verifies that DISABLE_DEFAULT_ARGOCD_CONSOLELINK disables the ConsoleLink, and it tolerates improper values and can be re-enabled", func() { + + if fixture.EnvLocalRun() { + Skip("skipping as LOCAL_RUN is set, which implies we are running the operator locally. When running locally, there is no Subscription or Deployment upon which we can set the DISABLE_DEFAULT_ARGOCD_CONSOLELINK env var") + return + } + + By("verifying default openshift-gitops Argo CD and ConsoleLink exist") + + argocd, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(argocd, "2m", "5s").Should(argocdFixture.BeAvailable()) + + consoleLink := &consolev1.ConsoleLink{ObjectMeta: metav1.ObjectMeta{Name: "argocd"}} + Eventually(consoleLink).Should(k8sFixture.ExistByName()) + + By("setting DISABLE_DEFAULT_ARGOCD_CONSOLELINK to true in operator") + fixture.SetEnvInOperatorSubscriptionOrDeployment("DISABLE_DEFAULT_ARGOCD_CONSOLELINK", "true") + + By("verifying ConsoleLink is deleted") + + Eventually(consoleLink, "60s", "5s").Should(k8sFixture.NotExistByName()) + Consistently(consoleLink).Should(k8sFixture.NotExistByName()) + + By("verifying DISABLE_DEFAULT_ARGOCD_CONSOLELINK has the value 'true'") + Eventually(func() bool { + val, err := fixture.GetEnvInOperatorSubscriptionOrDeployment("DISABLE_DEFAULT_ARGOCD_CONSOLELINK") + if err != nil { + GinkgoWriter.Println(err) + return false + } + if val == nil { + return false + } + return *val == "true" + }).Should(BeTrue(), "DISABLE_DEFAULT_ARGOCD_CONSOLELINK should be true") + + By("setting DISABLE_DEFAULT_ARGOCD_CONSOLELINK to false") + fixture.SetEnvInOperatorSubscriptionOrDeployment("DISABLE_DEFAULT_ARGOCD_CONSOLELINK", "false") + + By("verifying ConsoleLink exists") + + Eventually(consoleLink, "60s", "5s").Should(k8sFixture.ExistByName()) + + By("verifying DISABLE_DEFAULT_ARGOCD_CONSOLELINK is 'false'") + + Eventually(func() bool { + val, err := fixture.GetEnvInOperatorSubscriptionOrDeployment("DISABLE_DEFAULT_ARGOCD_CONSOLELINK") + if err != nil { + GinkgoWriter.Println(err) + return false + } + if val == nil { + return false + } + return *val == "false" + }).Should(BeTrue(), "DISABLE_DEFAULT_ARGOCD_CONSOLELINK should be false") + + By("setting DISABLE_DEFAULT_ARGOCD_CONSOLELINK to an empty value") + + fixture.SetEnvInOperatorSubscriptionOrDeployment("DISABLE_DEFAULT_ARGOCD_CONSOLELINK", "") + + By("verifying ConsoleLink continues to exist") + + Eventually(consoleLink, "60s", "5s").Should(k8sFixture.ExistByName()) + Consistently(consoleLink).Should(k8sFixture.ExistByName()) + + By("verifying DISABLE_DEFAULT_ARGOCD_CONSOLELINK has an empty value") + + Eventually(func() bool { + val, err := fixture.GetEnvInOperatorSubscriptionOrDeployment("DISABLE_DEFAULT_ARGOCD_CONSOLELINK") + if err != nil { + GinkgoWriter.Println(err) + return false + } + if val == nil { + return false + } + return *val == "" + }).Should(BeTrue(), "DISABLE_DEFAULT_ARGOCD_CONSOLELINK should be empty, but exist") + + By("cleaning up operator and ensuring ConsoleLink exists") + + Expect(fixture.RestoreSubcriptionToDefault()).To(Succeed()) + + Eventually(consoleLink).Should(k8sFixture.ExistByName()) + Consistently(consoleLink).Should(k8sFixture.ExistByName()) + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-085_validate_dynamic_plugin_installation_test.go b/test/openshift/e2e/ginkgo/sequential/1-085_validate_dynamic_plugin_installation_test.go new file mode 100644 index 000000000..6324e56b0 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-085_validate_dynamic_plugin_installation_test.go @@ -0,0 +1,132 @@ +package sequential + +import ( + "context" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + clusterserviceversionFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/clusterserviceversion" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + osFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/os" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-085_validate_dynamic_plugin_installation", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("enables Dynamic plugin via modifying CSV, then verifies the gitops plugin resources are installed as expected", func() { + + if fixture.EnvNonOLM() { + Skip("Skipping test as NON_OLM env var is set. This test requires operator to running via CSV.") + return + } + + if fixture.EnvLocalRun() { + Skip("Skipping test as LOCAL_RUN env var is set. There is no CSV to modify in this case.") + return + } + + // Find CSV + var csv *olmv1alpha1.ClusterServiceVersion + var csvList olmv1alpha1.ClusterServiceVersionList + Expect(k8sClient.List(ctx, &csvList, client.InNamespace("openshift-gitops-operator"))).To(Succeed()) + + for idx := range csvList.Items { + idxCSV := csvList.Items[idx] + if strings.Contains(idxCSV.Name, "gitops-operator") { + csv = &idxCSV + break + } + } + Expect(csv).ToNot(BeNil()) + + // At the end of the test, ensure the env var is removed + defer func() { + Expect(fixture.RemoveDynamicPluginFromCSV(ctx, k8sClient)).To(Succeed()) + }() + + var ocVersion string + + output, err := osFixture.ExecCommand("oc", "version") + Expect(err).ToNot(HaveOccurred()) + + for _, line := range strings.Split(output, "\n") { + + if strings.Contains(line, "Server Version:") { + ocVersion = strings.TrimSpace(line[strings.Index(line, ":")+1:]) + break + } + } + Expect(ocVersion).ToNot(BeEmpty()) + + if strings.Contains(ocVersion, "4.15.") { + Skip("skipping this test as OCP version is 4.15") + return + } + + By("adding DYNAMIC_PLUGIN_START_OCP_VERSION to CSV operator Deployment env var list") + + clusterserviceversionFixture.Update(csv, func(csv *olmv1alpha1.ClusterServiceVersion) { + + envList := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Env + envList = append(envList, corev1.EnvVar{Name: "DYNAMIC_PLUGIN_START_OCP_VERSION", Value: ocVersion}) + + csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Env = envList + + }) + + By("verifying the plugin's Deployment, ConfigMap, Secret, Service, and other resources have expected values") + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "gitops-plugin", Namespace: "openshift-gitops"}} + Eventually(depl, "3m", "5s").Should(k8sFixture.ExistByName()) + Eventually(depl, "60s", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + + configMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "httpd-cfg", Namespace: "openshift-gitops"}} + Eventually(configMap).Should(k8sFixture.ExistByName()) + + Expect(configMap).To( + And(k8sFixture.HaveLabelWithValue("app", "gitops-plugin"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/part-of", "gitops-plugin"))) + + secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "console-serving-cert", Namespace: "openshift-gitops"}} + Eventually(secret).Should(k8sFixture.ExistByName()) + + service := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "gitops-plugin", Namespace: "openshift-gitops"}} + Eventually(service).Should(k8sFixture.ExistByName()) + + match := false + for _, port := range service.Spec.Ports { + if port.Name == "tcp-9001" { + Expect(port.Port).To(Equal(int32(9001))) + Expect(string(port.Protocol)).To(Equal("TCP")) + Expect(port.TargetPort.IntValue()).To(Equal(9001)) + match = true + } + } + Expect(match).To(BeTrue()) + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-086_validate_default_argocd_role_test.go b/test/openshift/e2e/ginkgo/sequential/1-086_validate_default_argocd_role_test.go new file mode 100644 index 000000000..5bbcbd9aa --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-086_validate_default_argocd_role_test.go @@ -0,0 +1,157 @@ +package sequential + +import ( + "context" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-086_validate_default_argocd_role", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that Argo CD roles are defined as expected in argocd-rbac-cm, based on values in ArgoCD .spec.rbac.defaultPolicy", func() { + + By("verifying default ArgoCD in openshift-gitops is running and has defined expected RBAC values in ConfigMap argocd-rbac-cm") + + argocd, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(argocd, "4m", "5s").Should(argocdFixture.BeAvailable()) + Expect(argocd.Spec.Server.Route.Enabled).To(BeTrue()) + + configMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-rbac-cm", Namespace: "openshift-gitops"}} + Eventually(configMap).Should(k8sFixture.ExistByName()) + Expect(configMap).To( + And( + k8sFixture.HaveLabelWithValue("app.kubernetes.io/managed-by", "openshift-gitops"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/name", "argocd-rbac-cm"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/part-of", "argocd"), + )) + + Expect(strings.TrimSpace(configMap.Data["policy.csv"])).To(Equal("g, system:cluster-admins, role:admin\ng, cluster-admins, role:admin")) + Expect(configMap.Data["policy.default"]).To(Equal("")) + Expect(configMap.Data["scopes"]).To(Equal("[groups]")) + + By("creating 3 ArgoCD instances in 3 different namespaces, with different RBAC policies") + + test_1_086_customNS := fixture.CreateNamespace("test-1-086-custom") + test_1_086_custom2NS := fixture.CreateNamespace("test-1-086-custom2") + test_1_086_custom3NS := fixture.CreateNamespace("test-1-086-custom3") + + argoCD_default_policy := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-default-policy", Namespace: test_1_086_customNS.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD_default_policy)).To(Succeed()) + + argoCD_default_policy_empty := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-default-policy-empty", Namespace: test_1_086_custom2NS.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + RBAC: argov1beta1api.ArgoCDRBACSpec{ + DefaultPolicy: ptr.To(""), + }, + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD_default_policy_empty)).To(Succeed()) + + argoCD_default_policy_admin := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd-default-policy-admin", Namespace: test_1_086_custom3NS.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + RBAC: argov1beta1api.ArgoCDRBACSpec{ + DefaultPolicy: ptr.To("role:admin"), + }, + Server: argov1beta1api.ArgoCDServerSpec{ + Route: argov1beta1api.ArgoCDRouteSpec{ + Enabled: true, + }, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD_default_policy_admin)).To(Succeed()) + + By("verifying Argo CD instances become available") + + Eventually(argoCD_default_policy, "2m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCD_default_policy_empty, "2m", "5s").Should(argocdFixture.BeAvailable()) + Eventually(argoCD_default_policy_admin, "2m", "5s").Should(argocdFixture.BeAvailable()) + + By("verifying argocd-rbac-cm ConfigMap contains the expected values in each namespace") + + configMap_test_1_086_custom := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-rbac-cm", Namespace: "test-1-086-custom"}} + Eventually(configMap_test_1_086_custom).Should(k8sFixture.ExistByName()) + Expect(configMap_test_1_086_custom).To( + And( + k8sFixture.HaveLabelWithValue("app.kubernetes.io/managed-by", "argocd-default-policy"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/name", "argocd-rbac-cm"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/part-of", "argocd"), + )) + + Expect(strings.TrimSpace(configMap_test_1_086_custom.Data["policy.csv"])).To(Equal("")) + Expect(configMap_test_1_086_custom.Data["policy.default"]).To(Equal("role:readonly")) + Expect(configMap_test_1_086_custom.Data["scopes"]).To(Equal("[groups]")) + + configMap_test_1_086_custom2 := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-rbac-cm", Namespace: "test-1-086-custom2"}} + Eventually(configMap_test_1_086_custom2).Should(k8sFixture.ExistByName()) + Expect(configMap_test_1_086_custom2).To( + And( + k8sFixture.HaveLabelWithValue("app.kubernetes.io/managed-by", "argocd-default-policy-empty"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/name", "argocd-rbac-cm"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/part-of", "argocd"), + )) + + Expect(strings.TrimSpace(configMap_test_1_086_custom2.Data["policy.csv"])).To(Equal("")) + Expect(configMap_test_1_086_custom2.Data["policy.default"]).To(Equal("")) + Expect(configMap_test_1_086_custom2.Data["scopes"]).To(Equal("[groups]")) + + configMap_test_1_086_custom3 := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-rbac-cm", Namespace: "test-1-086-custom3"}} + Eventually(configMap_test_1_086_custom3).Should(k8sFixture.ExistByName()) + Expect(configMap_test_1_086_custom3).To( + And( + k8sFixture.HaveLabelWithValue("app.kubernetes.io/managed-by", "argocd-default-policy-admin"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/name", "argocd-rbac-cm"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/part-of", "argocd"), + )) + + Expect(strings.TrimSpace(configMap_test_1_086_custom3.Data["policy.csv"])).To(Equal("")) + Expect(configMap_test_1_086_custom3.Data["policy.default"]).To(Equal("role:admin")) + Expect(configMap_test_1_086_custom3.Data["scopes"]).To(Equal("[groups]")) + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-100_validate_rollouts_resources_creation_test.go b/test/openshift/e2e/ginkgo/sequential/1-100_validate_rollouts_resources_creation_test.go new file mode 100644 index 000000000..ce0a655d8 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-100_validate_rollouts_resources_creation_test.go @@ -0,0 +1,72 @@ +package sequential + +import ( + "context" + + rolloutmanagerv1alpha1 "github.com/argoproj-labs/argo-rollouts-manager/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + deploymentFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/deployment" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-100_validate_rollouts_resources_creation", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("creates a cluster-scopes Argo Rollouts instance and verifies the expected K8s resources are created", func() { + + By("creating simple cluster-scoped Argo Rollouts instance via RolloutManager in openshift-gitops namespace") + + rm := &rolloutmanagerv1alpha1.RolloutManager{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example-rollout-manager", + Namespace: "openshift-gitops", + }, + } + Expect(k8sClient.Create(ctx, rm)).To(Succeed()) + + By("verifying all the expected K8s resources exist") + Eventually(&corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts", Namespace: "openshift-gitops"}}, "120s", "1s").Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts-aggregate-to-admin", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts-aggregate-to-edit", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts-aggregate-to-view", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts-notification-secret", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + depl := &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts", Namespace: "openshift-gitops"}} + Eventually(depl).Should(k8sFixture.ExistByName()) + Eventually(depl, "4m", "5s").Should(deploymentFixture.HaveReadyReplicas(1)) + + Eventually(&corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts-metrics", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-101_validate_rollout_policyrules_test.go b/test/openshift/e2e/ginkgo/sequential/1-101_validate_rollout_policyrules_test.go new file mode 100644 index 000000000..446a1529a --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-101_validate_rollout_policyrules_test.go @@ -0,0 +1,176 @@ +package sequential + +import ( + "context" + + rolloutmanagerv1alpha1 "github.com/argoproj-labs/argo-rollouts-manager/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-101_validate_rollout_policyrules", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifying Rollouts operator creates the expected policy rules", func() { + + By("creating cluster-scoped Argo Rollouts instance in openshift-gitops RolloutManager") + rm := &rolloutmanagerv1alpha1.RolloutManager{ + ObjectMeta: metav1.ObjectMeta{ + Name: "example-rollout-manager", + Namespace: "openshift-gitops", + }, + } + Expect(k8sClient.Create(ctx, rm)).To(Succeed()) + + By("verifying Rollouts ClusterRole contains expected policy rules") + clusterRole := &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: "argo-rollouts"}} + Eventually(clusterRole, "1m", "5s").Should(k8sFixture.ExistByName()) + Expect(clusterRole).To( + And( + k8sFixture.HaveLabelWithValue("app.kubernetes.io/component", "argo-rollouts"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/name", "argo-rollouts"), + k8sFixture.HaveLabelWithValue("app.kubernetes.io/part-of", "argo-rollouts"), + )) + + Expect(clusterRole.Rules).To(Equal( + []rbacv1.PolicyRule{ + { + APIGroups: []string{"argoproj.io"}, + Resources: []string{"rollouts", "rollouts/status", "rollouts/finalizers"}, + Verbs: []string{"get", "list", "watch", "update", "patch"}, + }, + { + APIGroups: []string{"argoproj.io"}, + Resources: []string{"analysisruns", "analysisruns/finalizers", "experiments", "experiments/finalizers"}, + Verbs: []string{"create", "get", "list", "watch", "update", "patch", "delete"}, + }, + { + APIGroups: []string{"argoproj.io"}, + Resources: []string{"analysistemplates", "clusteranalysistemplates"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"apps"}, + Resources: []string{"replicasets"}, + Verbs: []string{"create", "get", "list", "watch", "update", "patch", "delete"}, + }, + { + APIGroups: []string{"", "apps"}, + Resources: []string{"deployments", "podtemplates"}, + Verbs: []string{"get", "list", "watch", "update", "patch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"services"}, + Verbs: []string{"get", "list", "watch", "patch", "create", "delete"}, + }, + { + APIGroups: []string{"coordination.k8s.io"}, + Resources: []string{"leases"}, + Verbs: []string{"create", "get", "update"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets", "configmaps"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"pods"}, + Verbs: []string{"list", "update", "watch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"pods/eviction"}, + Verbs: []string{"create"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"events"}, + Verbs: []string{"create", "update", "patch"}, + }, + { + APIGroups: []string{"networking.k8s.io", "extensions"}, + Resources: []string{"ingresses"}, + Verbs: []string{"create", "get", "list", "watch", "patch"}, + }, + { + APIGroups: []string{"batch"}, + Resources: []string{"jobs"}, + Verbs: []string{"create", "get", "list", "watch", "update", "patch", "delete"}, + }, + { + APIGroups: []string{"networking.istio.io"}, + Resources: []string{"virtualservices", "destinationrules"}, + Verbs: []string{"watch", "get", "update", "patch", "list"}, + }, + { + APIGroups: []string{"split.smi-spec.io"}, + Resources: []string{"trafficsplits"}, + Verbs: []string{"create", "watch", "get", "update", "patch"}, + }, + { + APIGroups: []string{"getambassador.io", "x.getambassador.io"}, + Resources: []string{"mappings", "ambassadormappings"}, + Verbs: []string{"create", "watch", "get", "update", "list", "delete"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"endpoints"}, + Verbs: []string{"get"}, + }, + { + APIGroups: []string{"elbv2.k8s.aws"}, + Resources: []string{"targetgroupbindings"}, + Verbs: []string{"list", "get"}, + }, + { + APIGroups: []string{"appmesh.k8s.aws"}, + Resources: []string{"virtualservices"}, + Verbs: []string{"watch", "get", "list"}, + }, + { + APIGroups: []string{"appmesh.k8s.aws"}, + Resources: []string{"virtualnodes", "virtualrouters"}, + Verbs: []string{"watch", "get", "list", "update", "patch"}, + }, + { + APIGroups: []string{"traefik.containo.us", "traefik.io"}, + Resources: []string{"traefikservices"}, + Verbs: []string{"watch", "get", "update"}, + }, + { + APIGroups: []string{"apisix.apache.org"}, + Resources: []string{"apisixroutes"}, + Verbs: []string{"watch", "get", "update"}, + }, + { + APIGroups: []string{"route.openshift.io"}, + Resources: []string{"routes"}, + Verbs: []string{"create", "watch", "get", "update", "patch", "list"}, + }, + })) + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-105_validate_label_selector_test.go b/test/openshift/e2e/ginkgo/sequential/1-105_validate_label_selector_test.go new file mode 100644 index 000000000..24c57f816 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-105_validate_label_selector_test.go @@ -0,0 +1,137 @@ +package sequential + +import ( + "context" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-105_validate_label_selector", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("ensures that ARGOCD_LABEL_SELECTOR controls which ArgoCD CRs are reconciled via operator", func() { + + if fixture.EnvLocalRun() { + Skip("Skipping as LOCAL_RUN is set. In this case, there is no operator Subscription or Deployment to modify.") + return + } + + By("adding ARGOCD_LABEL_SELECTOR foo=bar to Operator") + fixture.SetEnvInOperatorSubscriptionOrDeployment("ARGOCD_LABEL_SELECTOR", "foo=bar") + + defer func() { // Restore subscription to default after test + Expect(fixture.RestoreSubcriptionToDefault()).To(Succeed()) + }() + + By("creating new namespace-scoped ArgoCD instance in test-argocd") + + ns := fixture.CreateNamespace("test-argocd") + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test1", + Namespace: ns.Name, + Labels: map[string]string{"example": "basic"}, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + + Consistently(argoCD, "2m", "5s").ShouldNot(argocdFixture.BeAvailable(), "since this ArgoCD does not have foo=bar, it should not be reconciled and thus not become available") + + By("adding foo=bar label to ArgoCD, which should now cause the ArgoCD to be reconciled") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + if ac.Labels == nil { + ac.Labels = map[string]string{} + } + ac.Labels["foo"] = "bar" + }) + + By("verifying that ArgoCD becomes available") + Eventually(argoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + By("adding custom rbac to .spec.rbac of ArgoCD") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.RBAC = argov1beta1api.ArgoCDRBACSpec{ + Policy: ptr.To("g, system:cluster-admins, role:admin\ng, cluster-admins, role:admin"), + Scopes: ptr.To("[email]"), + } + }) + + By("verifying ArgoCD becomes available after .spec update and that argocd-rbac-cm ConfigMap has expected values from ArgoCD CR rbac field") + + Eventually(argoCD, "1m", "5s").Should(argocdFixture.BeAvailable()) + + configMap := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-rbac-cm", Namespace: ns.Name}} + Eventually(configMap).Should(k8sFixture.ExistByName()) + Expect(strings.TrimSpace(configMap.Data["policy.csv"])).To(Equal("g, system:cluster-admins, role:admin\ng, cluster-admins, role:admin")) + Expect(configMap.Data["policy.default"]).To(Equal("role:readonly")) + Expect(configMap.Data["scopes"]).To(Equal("[email]")) + + By("removing foo label from ArgoCD") + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + delete(ac.Labels, "foo") + }) + + By("updating RBAC policy field of ArgoCD") + + argocdFixture.Update(argoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.RBAC = argov1beta1api.ArgoCDRBACSpec{ + Policy: ptr.To("g, system:cluster-admins, role:admin\ng, cluster-admins, role:admin"), + Scopes: ptr.To("[people]"), + } + }) + + By("verifying that Argo CD argocd-rbac-cm ConfigMap has not changed, since ArgoCD does not have the required foo=bar label") + + configMap = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-rbac-cm", Namespace: ns.Name}} + Eventually(configMap).Should(k8sFixture.ExistByName()) + Expect(strings.TrimSpace(configMap.Data["policy.csv"])).To(Equal("g, system:cluster-admins, role:admin\ng, cluster-admins, role:admin")) + Expect(configMap.Data["policy.default"]).To(Equal("role:readonly")) + Expect(configMap.Data["scopes"]).To(Equal("[email]")) + + Consistently(func() bool { + if err := k8sClient.Get(ctx, client.ObjectKeyFromObject(configMap), configMap); err != nil { + GinkgoWriter.Println(err) + return false + } + + // Fail if scopes is '[people]' even once + if configMap.Data["scopes"] == "[people]" { + return false + } + + return true + + }).Should(BeTrue(), "wait 10 seconds to ensure the ArgoCD is never reconcield") + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-106_validate_argocd_metrics_controller_test.go b/test/openshift/e2e/ginkgo/sequential/1-106_validate_argocd_metrics_controller_test.go new file mode 100644 index 000000000..e9d3eb0ba --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-106_validate_argocd_metrics_controller_test.go @@ -0,0 +1,97 @@ +package sequential + +import ( + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + monitoringv1 "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + k8sFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/k8s" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-106_validate_argocd_metrics_controller", func() { + + BeforeEach(func() { + fixture.EnsureSequentialCleanSlate() + }) + + // expectMetricsEnabled verifies that ArgoCD monitoring is enabled in 'openshift-gitops' ns + expectMetricsEnabled := func() { + + openshiftGitopsNS := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops"}} + Eventually(openshiftGitopsNS).Should(k8sFixture.HaveLabelWithValue("openshift.io/cluster-monitoring", "true")) + + // ServiceMonitors + + Eventually(&monitoringv1.ServiceMonitor{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&monitoringv1.ServiceMonitor{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-repo-server", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + Eventually(&monitoringv1.ServiceMonitor{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-server", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + // Roles/Bindings + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-read", Namespace: "openshift-gitops"}}, "30s", "1s").Should(k8sFixture.ExistByName()) + + Eventually(&rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-prometheus-k8s-read-binding", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + // PrometheusRule + Eventually(&monitoringv1.PrometheusRule{ObjectMeta: metav1.ObjectMeta{Name: "gitops-operator-argocd-alerts", Namespace: "openshift-gitops"}}).Should(k8sFixture.ExistByName()) + + } + + It("verifies Argo CD metrics can be disabled and re-enabled", func() { + + By("verifying Argo CD metrics are enabled by default in openshift-gitops") + + defaultArgoCD, err := argocdFixture.GetOpenShiftGitOpsNSArgoCD() + Expect(err).ToNot(HaveOccurred()) + Eventually(defaultArgoCD, "3m", "5s").Should(argocdFixture.BeAvailable()) + + expectMetricsEnabled() + + By("disabling metrics via ArgoCD CR .spec.monitoring.disableMetrics") + + argocdFixture.Update(defaultArgoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Monitoring.DisableMetrics = ptr.To(true) + }) + + By("verifying all metrics resources are in disabled state") + openshiftGitopsNS := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: defaultArgoCD.Namespace}} + + Eventually(openshiftGitopsNS).Should(k8sFixture.NotHaveLabelWithValue("openshift.io/cluster-monitoring", "true")) + Consistently(openshiftGitopsNS).Should(k8sFixture.NotHaveLabelWithValue("openshift.io/cluster-monitoring", "true")) + + Eventually(&monitoringv1.ServiceMonitor{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Eventually(&monitoringv1.ServiceMonitor{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-repo-server", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Eventually(&monitoringv1.ServiceMonitor{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-server", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Eventually(&rbacv1.Role{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-read", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Eventually(&rbacv1.RoleBinding{ObjectMeta: metav1.ObjectMeta{Name: "openshift-gitops-prometheus-k8s-read-binding", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + Eventually(&monitoringv1.PrometheusRule{ObjectMeta: metav1.ObjectMeta{Name: "gitops-operator-argocd-alerts", Namespace: "openshift-gitops"}}).Should(k8sFixture.NotExistByName()) + + By("re-enabling metrics") + argocdFixture.Update(defaultArgoCD, func(ac *argov1beta1api.ArgoCD) { + ac.Spec.Monitoring.DisableMetrics = ptr.To(false) + }) + + By("verifying metrics are re-enabled") + + expectMetricsEnabled() + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/1-107_validate_redis_scc.go b/test/openshift/e2e/ginkgo/sequential/1-107_validate_redis_scc.go new file mode 100644 index 000000000..4fdb5e1e7 --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/1-107_validate_redis_scc.go @@ -0,0 +1,86 @@ +package sequential + +import ( + "context" + "strings" + + argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture" + argocdFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/argocd" + nodeFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/node" + "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("GitOps Operator Sequential E2E Tests", func() { + + Context("1-107_validate_redis_scc", func() { + + var ( + ctx context.Context + k8sClient client.Client + ) + + BeforeEach(func() { + + fixture.EnsureSequentialCleanSlate() + k8sClient, _ = utils.GetE2ETestKubeClient() + ctx = context.Background() + }) + + It("verifies that when Argo CD has HA enabled that the redis pods use restricted-v2 security policy", func() { + + By("verifying we are running on a cluster with at least 3 nodes. This is required for Redis HA") + nodeFixture.ExpectHasAtLeastXNodes(3) + // Note: Redis HA requires a cluster which contains multiple nodes + + By("creating simple namespace-scoped Argo CD instance with HA enabled") + ns, cleanupFunc := fixture.CreateRandomE2ETestNamespaceWithCleanupFunc() + defer cleanupFunc() + + argoCD := &argov1beta1api.ArgoCD{ + ObjectMeta: metav1.ObjectMeta{Name: "argocd", Namespace: ns.Name}, + Spec: argov1beta1api.ArgoCDSpec{ + HA: argov1beta1api.ArgoCDHASpec{ + Enabled: true, + }, + }, + } + Expect(k8sClient.Create(ctx, argoCD)).To(Succeed()) + By("verifying HA Redis becomes available") + Eventually(argoCD, "6m", "5s").Should(argocdFixture.HaveRedisStatus("Running")) // redis HA takes a while + + By("verifying that argocd-redis-ha pod has scc of restricted-v2") + var podList corev1.PodList + Expect(k8sClient.List(ctx, &podList, &client.ListOptions{Namespace: ns.Name})).To(Succeed()) + + matchFound := false + for _, pod := range podList.Items { + if !strings.Contains(pod.Name, "argocd-redis-ha") { + continue + } + Expect(pod.ObjectMeta.Annotations["openshift.io/scc"]).To(Equal("restricted-v2")) + matchFound = true + } + Expect(matchFound).To(BeTrue()) + + By("verifying that argocd-redis-ha-haproxy pod has scc of restricted-v2") + matchFound = false + for _, pod := range podList.Items { + if !strings.Contains(pod.Name, "argocd-redis-ha-haproxy") { + continue + } + Expect(pod.ObjectMeta.Annotations["openshift.io/scc"]).To(Equal("restricted-v2")) + matchFound = true + } + Expect(matchFound).To(BeTrue()) + + }) + + }) + +}) diff --git a/test/openshift/e2e/ginkgo/sequential/suite_test.go b/test/openshift/e2e/ginkgo/sequential/suite_test.go new file mode 100644 index 000000000..508003d9e --- /dev/null +++ b/test/openshift/e2e/ginkgo/sequential/suite_test.go @@ -0,0 +1,48 @@ +/* +Copyright 2021. + +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 sequential + +import ( + "testing" + + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) + // to ensure that exec-entrypoint and run can make use of them. + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + _ "k8s.io/client-go/plugin/pkg/client/auth" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +func TestSequentialSuite(t *testing.T) { + + RegisterFailHandler(Fail) + RunSpecs(t, "Sequential Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + +}) + +var _ = AfterSuite(func() { +})