test(e2e): environment setup (#43)

Create the CI and testing infrastructure for e2e testing. Running the ci
task now will push the plugin and sidecar images to a local registry,
start kind, install the CloudNativePG and cert-manager operators, and
then install the plugin-barman-cloud one.

No actual test is implemented.

Signed-off-by: Francesco Canovai <francesco.canovai@enterprisedb.com>
This commit is contained in:
Francesco Canovai 2024-11-14 09:44:18 +01:00 committed by GitHub
parent b7c4a4bb10
commit 74bc9e221e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 1455 additions and 312 deletions

View File

@ -8,12 +8,35 @@ jobs:
ci: ci:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Cleanup Disk
uses: jlumbroso/free-disk-space@v1.3.1
with:
android: true
dotnet: true
haskell: true
tool-cache: true
large-packages: false
swap-storage: false
- name: Cleanup docker cache
run: |
echo "-------------Disk info before cleanup----------------"
df -h
echo "-----------------------------------------------------"
docker system prune -a -f
echo "-------------Disk info after cleanup----------------"
df -h
echo "-----------------------------------------------------"
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
# We need the full history for the commitlint task # We need the full history for the commitlint task
with: with:
fetch-depth: 0 fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
# TODO: remove this when we daggerize the e2e
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23.x'
- name: Install Task - name: Install Task
uses: arduino/setup-task@v2 uses: arduino/setup-task@v2
- name: Install Dagger - name: Install Dagger

5
.gitignore vendored
View File

@ -34,3 +34,8 @@ go.work
# Taskfile cache # Taskfile cache
.task .task
# E2e test artifacts
test/e2e/bin
# Test registry certificates
certs/

View File

@ -1,5 +1,12 @@
version: 3 version: 3
# Environment variables that are shared across tasks.
env:
REGISTRY_NETWORK: barman-cloud-plugin
REGISTRY_NAME: registry.barman-cloud-plugin
REGISTRY_PORT: 5000
DAGGER_ENGINE_CONTAINER_NAME: e2e-dagger-engine
tasks: tasks:
lint: lint:
desc: Run golangci-lint desc: Run golangci-lint
@ -66,25 +73,111 @@ tasks:
sources: sources:
- ./**/*.go - ./**/*.go
generate-certs:
desc: Generate certificates for the local registry
run: once
cmds:
- >
mkdir -p certs &&
pushd certs &&
openssl genrsa -out ca-key.pem 4096 &&
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem \
-subj "/O=CloudNativePG/OU=Barman Cloud Plugin Testing" &&
openssl genrsa -out server-key.pem 4096 &&
openssl req -subj "/CN=${REGISTRY_NAME}" -sha256 -new -key server-key.pem -out server.csr &&
echo subjectAltName = DNS:${REGISTRY_NAME},IP:127.0.0.1 >> extfile.cnf &&
echo extendedKeyUsage = serverAuth >> extfile.cnf &&
openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem -extfile extfile.cnf &&
popd
status:
- test -f certs/ca-key.pem
- test -f certs/ca.pem
- test -f certs/server-key.pem
- test -f certs/server.csr
- test -f certs/server-cert.pem
start-build-network:
desc: Create a docker network for image building used by the dagger engine and the registry
run: once
cmds:
- docker network create ${REGISTRY_NETWORK}
status:
- docker network inspect ${REGISTRY_NETWORK}
start-registry:
desc: Start a container registry
run: once
deps:
- generate-certs
- start-build-network
env:
# TODO: renovate
REGISTRY_VERSION: 2
cmds:
- >
docker run -d --name ${REGISTRY_NAME}
-p ${REGISTRY_PORT}:5000
--network ${REGISTRY_NETWORK}
-v $(pwd)/certs:/certs
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server-cert.pem -e REGISTRY_HTTP_TLS_KEY=/certs/server-key.pem
registry:${REGISTRY_VERSION}
status:
- \[ "$(docker inspect -f {{`'{{.State.Running}}'`}} "${REGISTRY_NAME}" 2> /dev/null )" == 'true' \]
# Start a dagger engine that mounts the CA certificate for the local registry.
start-dagger-engine-for-local-builds:
desc: Start a dagger engine mounting the CA
run: once
deps:
- generate-certs
- start-build-network
env:
# TODO: renovate
DAGGER_ENGINE_IMAGE: registry.dagger.io/engine:v0.13.6
cmds:
- >
docker run -d -v /var/lib/dagger --name "${DAGGER_ENGINE_CONTAINER_NAME}"
--network=${REGISTRY_NETWORK}
-v $(pwd)/certs/ca.pem:/usr/local/share/ca-certificates/ca.crt
--privileged ${DAGGER_ENGINE_IMAGE}
status:
- \[ "$(docker inspect -f {{`'{{.State.Running}}'`}} "${DAGGER_ENGINE_CONTAINER_NAME}" 2> /dev/null )" == 'true' \]
# We build an image and push it to a local registry.
# The name is always `plugin-barman-cloud:testing`.
build-plugin-image: build-plugin-image:
desc: Build the operator container image for the plugin desc: Build the operator container image for the plugin
deps:
- start-registry
- start-dagger-engine-for-local-builds
env: env:
# renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main # renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main
DAGGER_DOCKER_SHA: 4778f39b9cf56e0242c124000a563f9486dafa4b DAGGER_DOCKER_SHA: 4778f39b9cf56e0242c124000a563f9486dafa4b
_EXPERIMENTAL_DAGGER_RUNNER_HOST: docker-container://{{.DAGGER_ENGINE_CONTAINER_NAME}}
cmds: cmds:
- > - >
GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} GITHUB_REF= dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
build --dir . --file containers/Dockerfile.plugin --platform linux/amd64 image > /dev/null build --dir . --file containers/Dockerfile.plugin --platform linux/amd64
publish --ref ${REGISTRY_NAME}:${REGISTRY_PORT}/plugin-barman-cloud --tags testing
# We build an image and push it to a local registry.
# The name is always `sidecar-barman-cloud:testing`.
build-sidecar-image: build-sidecar-image:
desc: Build the sidecar container image for the plugin desc: Build the sidecar container image for the plugin
deps:
- start-registry
- start-dagger-engine-for-local-builds
env: env:
# renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main # renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main
DAGGER_DOCKER_SHA: 4778f39b9cf56e0242c124000a563f9486dafa4b DAGGER_DOCKER_SHA: 4778f39b9cf56e0242c124000a563f9486dafa4b
_EXPERIMENTAL_DAGGER_RUNNER_HOST: docker-container://{{.DAGGER_ENGINE_CONTAINER_NAME}}
cmds: cmds:
- > - >
GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} GITHUB_REF= dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64 image > /dev/null build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64
publish --ref ${REGISTRY_NAME}:${REGISTRY_PORT}/sidecar-barman-cloud --tags testing
build-images: build-images:
desc: Build the container images for the plugin desc: Build the container images for the plugin
@ -92,6 +185,21 @@ tasks:
- build-plugin-image - build-plugin-image
- build-sidecar-image - build-sidecar-image
# TODO: see if it is possible to daggerize this. It will have to manage docker to make kind work.
# TODO: add a task to clean up the kind cluster for new test runs.
# Run the e2e tests. This task will start a kind cluster, deploy the plugin, and run the tests.
# Running the e2e tests requires:
# * The registry to have a valid TLS certificate.
# * The registry to be in the same network of the dagger-engine.
# * The dagger-engine to mount the CA.
# * The kind cluster to mount the CA.
e2e:
desc: Run e2e tests
deps:
- build-images
cmds:
- go test -v ./test/e2e
ci: ci:
desc: Run the CI pipeline desc: Run the CI pipeline
deps: deps:
@ -100,7 +208,7 @@ tasks:
- uncommitted - uncommitted
- lint - lint
- go-test - go-test
- build-images - e2e
publish: publish:
desc: Build and publish a container image for the plugin desc: Build and publish a container image for the plugin
@ -125,12 +233,12 @@ tasks:
DAGGER_DOCKER_SHA: 4778f39b9cf56e0242c124000a563f9486dafa4b DAGGER_DOCKER_SHA: 4778f39b9cf56e0242c124000a563f9486dafa4b
cmds: cmds:
- > - >
dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
--registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD --registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD
build --dir . --file containers/Dockerfile.plugin --platform linux/amd64 --platform linux/arm64 build --dir . --file containers/Dockerfile.plugin --platform linux/amd64 --platform linux/arm64
publish --ref {{.PLUGIN_IMAGE_NAME}} --tags {{.IMAGE_VERSION}} publish --ref {{.PLUGIN_IMAGE_NAME}} --tags {{.IMAGE_VERSION}}
- > - >
dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA} dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
--registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD --registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD
build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64 --platform linux/arm64 build --dir . --file containers/Dockerfile.sidecar --platform linux/amd64 --platform linux/arm64
publish --ref {{.SIDECAR_IMAGE_NAME}} --tags {{.IMAGE_VERSION}} publish --ref {{.SIDECAR_IMAGE_NAME}} --tags {{.IMAGE_VERSION}}

54
go.mod
View File

@ -5,26 +5,31 @@ go 1.23
toolchain go1.23.1 toolchain go1.23.1
require ( require (
github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a github.com/cert-manager/cert-manager v1.16.1
github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241031170209-ad2b0d78a230 github.com/cloudnative-pg/barman-cloud v0.0.0-20241105055149-ae6c2408bd14
github.com/cloudnative-pg/cnpg-i v0.0.0-20241030162745-80b6d07403c1 github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241113134512-8608232c2813
github.com/cloudnative-pg/cnpg-i v0.0.0-20241109002750-8abd359df734
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19 github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19
github.com/cloudnative-pg/machinery v0.0.0-20241014090714-c27747f9974b github.com/cloudnative-pg/machinery v0.0.0-20241030141148-670a0f16f836
github.com/onsi/ginkgo/v2 v2.20.2 github.com/onsi/ginkgo/v2 v2.21.0
github.com/onsi/gomega v1.34.2 github.com/onsi/gomega v1.35.1
github.com/spf13/cobra v1.8.1 github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0 github.com/spf13/viper v1.19.0
google.golang.org/grpc v1.67.1 google.golang.org/grpc v1.68.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.31.2 k8s.io/api v0.31.2
k8s.io/apiextensions-apiserver v0.31.2
k8s.io/apimachinery v0.31.2 k8s.io/apimachinery v0.31.2
k8s.io/client-go v0.31.2 k8s.io/client-go v0.31.2
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078
sigs.k8s.io/controller-runtime v0.19.1 sigs.k8s.io/controller-runtime v0.19.1
sigs.k8s.io/kustomize/api v0.17.3
sigs.k8s.io/kustomize/kyaml v0.17.2
) )
require ( require (
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect
@ -37,6 +42,7 @@ require (
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect github.com/go-logr/zapr v1.3.0 // indirect
@ -51,12 +57,13 @@ require (
github.com/google/gnostic-models v0.6.8 // indirect github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 // indirect github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/imdario/mergo v0.3.16 // indirect github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
@ -70,11 +77,12 @@ require (
github.com/moby/spdystream v0.4.0 // indirect github.com/moby/spdystream v0.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.2 // indirect github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.78.1 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.59.1 // indirect github.com/prometheus/common v0.59.1 // indirect
@ -91,14 +99,16 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/thoas/go-funk v0.9.3 // indirect github.com/thoas/go-funk v0.9.3 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.28.0 // indirect go.opentelemetry.io/otel/sdk v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.starlark.net v0.0.0-20240925182052-1207426daebd // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
@ -109,21 +119,21 @@ require (
golang.org/x/term v0.25.0 // indirect golang.org/x/term v0.25.0 // indirect
golang.org/x/text v0.19.0 // indirect golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.25.0 // indirect golang.org/x/tools v0.26.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/protobuf v1.35.1 // indirect google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.31.2 // indirect
k8s.io/apiserver v0.31.2 // indirect k8s.io/apiserver v0.31.2 // indirect
k8s.io/component-base v0.31.2 // indirect k8s.io/component-base v0.31.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 // indirect k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect
sigs.k8s.io/gateway-api v1.1.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect

106
go.sum
View File

@ -2,8 +2,8 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
@ -12,20 +12,22 @@ 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/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cert-manager/cert-manager v1.16.1 h1:1ceFMqTtwiqY2vyfaRT85CNiVmK7pJjt3GebYCx9awY=
github.com/cert-manager/cert-manager v1.16.1/go.mod h1:MfLVTL45hFZsqmaT1O0+b2ugaNNQQZttSFV9hASHUb0=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= 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/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudnative-pg/api v0.0.0-20241004125129-98baa9f4957b h1:LZ9tIgKmWb8ZvyLg/J8ExXtmBtEWP2dr3Y4TU4nCq/w= github.com/cloudnative-pg/api v0.0.0-20241004125129-98baa9f4957b h1:LZ9tIgKmWb8ZvyLg/J8ExXtmBtEWP2dr3Y4TU4nCq/w=
github.com/cloudnative-pg/api v0.0.0-20241004125129-98baa9f4957b/go.mod h1:mzd1EvoLYy16jJdne6/4nwhoj7t4IZ0MqJMEH4mla8Q= github.com/cloudnative-pg/api v0.0.0-20241004125129-98baa9f4957b/go.mod h1:mzd1EvoLYy16jJdne6/4nwhoj7t4IZ0MqJMEH4mla8Q=
github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a h1:0v1ML9Eibfq3helbT9GtU0EstqFtG91k/MPO9azY5ME= github.com/cloudnative-pg/barman-cloud v0.0.0-20241105055149-ae6c2408bd14 h1:HX5pXyzVAqfjcDgCa1l8b4sumf7XYnGqiP+6XMgbB2E=
github.com/cloudnative-pg/barman-cloud v0.0.0-20240924124724-92831d48562a/go.mod h1:Jm0tOp5oB7utpt8wz6RfSv31h1mThOtffjfyxVupriE= github.com/cloudnative-pg/barman-cloud v0.0.0-20241105055149-ae6c2408bd14/go.mod h1:HPGwXHlatQEnb2HdsbGTZLEo8qlxKLdxTHiTeF9TTqw=
github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241031170209-ad2b0d78a230 h1:zRqm1WUMOqkPWGyvtvCAdWlQ+WTtb0iQA/rvCar27/E= github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241113134512-8608232c2813 h1:XWpr5y28JRwcA4BzxBkHFx7C8JDqOSdDIN7RbRdI6Dg=
github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241031170209-ad2b0d78a230/go.mod h1:La89zdElTqqZ5LXHFm/UjOwvS9iHSE8GuOW4fYUgHw8= github.com/cloudnative-pg/cloudnative-pg v1.24.1-0.20241113134512-8608232c2813/go.mod h1:f4hObdRVoQtMmVtWqZ6VDZBrI6ok9Td/UMhojQ+EPmk=
github.com/cloudnative-pg/cnpg-i v0.0.0-20241030162745-80b6d07403c1 h1:v3Vr+FH5BXmS7Eqx17u51oijZ4T7y62vUMCUAr7CffE= github.com/cloudnative-pg/cnpg-i v0.0.0-20241109002750-8abd359df734 h1:4jq/FUrlAKxu0Kw9PL5lj5Njq8pAnmUpP/kXKOrJAaE=
github.com/cloudnative-pg/cnpg-i v0.0.0-20241030162745-80b6d07403c1/go.mod h1:fAU7ySVzjpt/RZntxWZiWJCjaBJayzIxEnd0NuO7oQc= github.com/cloudnative-pg/cnpg-i v0.0.0-20241109002750-8abd359df734/go.mod h1:3U7miYasKr2rYCQzrn/IvbSQc0OpYF8ieZt2FKG4nv0=
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19 h1:qy+LrScvQpIwt4qeg9FfCJuoC9CbX/kpFGLF8vSobXg= github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19 h1:qy+LrScvQpIwt4qeg9FfCJuoC9CbX/kpFGLF8vSobXg=
github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19/go.mod h1:X6r1fRuUEIAv4+5SSBY2RmQ201K6GcptOXgnmaX/8tY= github.com/cloudnative-pg/cnpg-i-machinery v0.0.0-20241014090747-e9c2b3738d19/go.mod h1:X6r1fRuUEIAv4+5SSBY2RmQ201K6GcptOXgnmaX/8tY=
github.com/cloudnative-pg/machinery v0.0.0-20241014090714-c27747f9974b h1:4Q2VQsPlLHliJdi87zodQ0FHLd1cJINMm4N70eu8rRg= github.com/cloudnative-pg/machinery v0.0.0-20241030141148-670a0f16f836 h1:Hhg+I2QcaPNN5XaSsYb7Xw3PbQlvCA9eDY+SvVf902Q=
github.com/cloudnative-pg/machinery v0.0.0-20241014090714-c27747f9974b/go.mod h1:+mUFdys1IX+qwQUrV+/i56Tey/mYh8ZzWZYttwivRns= github.com/cloudnative-pg/machinery v0.0.0-20241030141148-670a0f16f836/go.mod h1:+mUFdys1IX+qwQUrV+/i56Tey/mYh8ZzWZYttwivRns=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/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.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -33,8 +35,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= 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 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@ -45,6 +47,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-faker/faker/v4 v4.4.1 h1:LY1jDgjVkBZWIhATCt+gkl0x9i/7wC61gZx73GTFb+Q= github.com/go-faker/faker/v4 v4.4.1 h1:LY1jDgjVkBZWIhATCt+gkl0x9i/7wC61gZx73GTFb+Q=
github.com/go-faker/faker/v4 v4.4.1/go.mod h1:HRLrjis+tYsbFtIHufEPTAIzcZiRu0rS9EYl2Ccwme4= github.com/go-faker/faker/v4 v4.4.1/go.mod h1:HRLrjis+tYsbFtIHufEPTAIzcZiRu0rS9EYl2Ccwme4=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@ -78,18 +82,20 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.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 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 h1:c5FlPPgxOn7kJz3VoPLkQYQXGBS3EklQ4Zfi57uOuqQ= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
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.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= 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/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@ -125,14 +131,16 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 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/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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -140,8 +148,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/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 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.2 h1:F/MALZ518KfI1zEg+Kg8/uTzoXKDyqw+LNC/5irJlJE= github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.78.1 h1:Fm9Z+FabnB+6EoGq15j+pyLmaK6hYrYOpBlTzOLTQ+E=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.77.2/go.mod h1:D0KY8md81DQKdaR/cXwnhoWB3MYYyc/UjvqE8GFkIvA= github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.78.1/go.mod h1:SvsRXw4m1F2vk7HquU5h475bFpke27mIUswfyw9u3ug=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
@ -159,6 +167,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/snorwin/jsonpatch v1.5.0 h1:0m56YSt9cHiJOn8U+OcqdPGcDQZmhPM/zsG7Dv5QQP0= github.com/snorwin/jsonpatch v1.5.0 h1:0m56YSt9cHiJOn8U+OcqdPGcDQZmhPM/zsG7Dv5QQP0=
github.com/snorwin/jsonpatch v1.5.0/go.mod h1:e0IDKlyFBLTFPqM0wa79dnMwjMs3XFvmKcrgCRpDqok= github.com/snorwin/jsonpatch v1.5.0/go.mod h1:e0IDKlyFBLTFPqM0wa79dnMwjMs3XFvmKcrgCRpDqok=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@ -178,9 +188,11 @@ github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8w
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 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.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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
@ -193,24 +205,28 @@ github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
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.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ=
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.starlark.net v0.0.0-20240925182052-1207426daebd h1:S+EMisJOHklQxnS3kqsY8jl2y5aF0FDEdcLnOw3q22E=
go.starlark.net v0.0.0-20240925182052-1207426daebd/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@ -254,20 +270,20 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/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-20200619180055-7c47624df98f/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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-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-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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -302,14 +318,20 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 h1:1dWzkmJrrprYvjGwh9kEUxmcUV/CtNU8QM7h1FLWQOo= k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38 h1:1dWzkmJrrprYvjGwh9kEUxmcUV/CtNU8QM7h1FLWQOo=
k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= k8s.io/kube-openapi v0.0.0-20240903163716-9e1beecbcb38/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY9mD9fNT47QO6HI= k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk=
sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
sigs.k8s.io/gateway-api v1.1.0 h1:DsLDXCi6jR+Xz8/xd0Z1PYl2Pn0TyaFMOPPZIj4inDM=
sigs.k8s.io/gateway-api v1.1.0/go.mod h1:ZH4lHrL2sDi0FHZ9jjneb8kKnGzFWyrTya35sWUTrRs=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= 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/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/kustomize/api v0.17.3 h1:6GCuHSsxq7fN5yhF2XrC+AAr8gxQwhexgHflOAD/JJU=
sigs.k8s.io/kustomize/api v0.17.3/go.mod h1:TuDH4mdx7jTfK61SQ/j1QZM/QWR+5rmEiNjvYlhzFhc=
sigs.k8s.io/kustomize/kyaml v0.17.2 h1:+AzvoJUY0kq4QAhH/ydPHHMRLijtUKiyVyh7fOSshr0=
sigs.k8s.io/kustomize/kyaml v0.17.2/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U=
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 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=

0
scripts/setup-kind.sh Normal file
View File

View File

@ -0,0 +1,11 @@
# Kind configuration file for running e2e tests
# Certificates must be mounted on each node because the registry is using TLS
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- hostPath: ../../certs/ca.pem
containerPath: /usr/local/share/ca-certificates/ca.crt
readOnly: true

View File

@ -17,13 +17,113 @@ limitations under the License.
package e2e package e2e
import ( import (
"context"
"fmt" "fmt"
"testing" "testing"
"time"
certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
apimachineryTypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
kustomizeTypes "sigs.k8s.io/kustomize/api/types"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/deployment"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/e2etestenv"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/kustomize"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
// We don't want multiple ginkgo nodes to run the setup concurrently, we use a single cluster for all tests.
var _ = SynchronizedBeforeSuite(func(ctx SpecContext) []byte {
var cl client.Client
var err error
if cl, err = e2etestenv.Setup(ctx,
e2etestenv.WithKindAdditionalNetworks([]string{"barman-cloud-plugin"})); err != nil {
Fail(fmt.Sprintf("failed to setup environment: %v", err))
}
const barmanCloudKustomizationPath = "./kustomize/kubernetes/"
barmanCloudKustomization := &kustomizeTypes.Kustomization{
Resources: []string{barmanCloudKustomizationPath},
Images: []kustomizeTypes.Image{
{
Name: "docker.io/library/plugin-barman-cloud",
NewName: "registry.barman-cloud-plugin:5000/plugin-barman-cloud",
NewTag: "testing",
},
},
SecretGenerator: []kustomizeTypes.SecretArgs{
{
GeneratorArgs: kustomizeTypes.GeneratorArgs{
Name: "plugin-barman-cloud",
Behavior: "replace",
KvPairSources: kustomizeTypes.KvPairSources{
LiteralSources: []string{"SIDECAR_IMAGE=registry.barman-cloud-plugin:5000/sidecar-barman-cloud:testing"},
},
},
},
},
}
scheme := runtime.NewScheme()
if err := corev1.AddToScheme(scheme); err != nil {
Fail(fmt.Sprintf("failed to add core/v1 to scheme: %v", err))
}
if err := apiextensionsv1.AddToScheme(scheme); err != nil {
Fail(fmt.Sprintf("failed to add apiextensions/v1 to scheme: %v", err))
}
if err := admissionregistrationv1.AddToScheme(scheme); err != nil {
Fail(fmt.Sprintf("failed to add admissionregistration/v1 to scheme: %v", err))
}
if err := rbacv1.AddToScheme(scheme); err != nil {
Fail(fmt.Sprintf("failed to add rbac/v1 to scheme: %v", err))
}
if err := appsv1.AddToScheme(scheme); err != nil {
Fail(fmt.Sprintf("failed to add apps/v1 to scheme: %v", err))
}
if err := certmanagerv1.AddToScheme(scheme); err != nil {
Fail(fmt.Sprintf("failed to add cert-manager.io/v1 to scheme: %v", err))
}
if err := kustomize.ApplyKustomization(ctx, cl, barmanCloudKustomization); err != nil {
Fail(fmt.Sprintf("failed to apply kustomization: %v", err))
}
const defaultTimeout = 1 * time.Minute
ctxDeploy, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
deploy := apimachineryTypes.NamespacedName{
Namespace: "cnpg-system",
Name: "barman-cloud",
}
err = wait.PollUntilContextCancel(ctxDeploy, 5*time.Second, false,
func(ctx context.Context) (bool, error) {
ready, err := deployment.IsReady(ctx, cl, deploy)
if err != nil {
return false, fmt.Errorf("failed to check if %s is ready: %w", deploy, err)
}
if ready {
return true, nil
}
return false, nil
})
if err != nil {
Fail(fmt.Sprintf("failed to wait for deployment to be ready: %v", err))
}
return []byte{}
}, func(_ []byte) {})
// Run e2e tests using the Ginkgo runner. // Run e2e tests using the Ginkgo runner.
func TestE2E(t *testing.T) { func TestE2E(t *testing.T) {
RegisterFailHandler(Fail) RegisterFailHandler(Fail)

View File

@ -17,108 +17,14 @@ limitations under the License.
package e2e package e2e
import ( import (
"fmt"
"os/exec"
"time"
"github.com/cloudnative-pg/plugin-barman-cloud/test/utils"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
const namespace = "plugin-barman-cloud-system" // const namespace = "plugin-barman-cloud-system"
var _ = Describe("controller", Ordered, func() { var _ = Describe("controller", Ordered, func() {
BeforeAll(func() { It("passes", func() {
By("installing prometheus operator") Expect(true).To(BeTrue())
Expect(utils.InstallPrometheusOperator()).To(Succeed())
By("installing the cert-manager")
Expect(utils.InstallCertManager()).To(Succeed())
By("creating manager namespace")
cmd := exec.Command("kubectl", "create", "ns", namespace)
_, _ = utils.Run(cmd)
})
AfterAll(func() {
By("uninstalling the Prometheus manager bundle")
utils.UninstallPrometheusOperator()
By("uninstalling the cert-manager bundle")
utils.UninstallCertManager()
By("removing manager namespace")
cmd := exec.Command("kubectl", "delete", "ns", namespace)
_, _ = utils.Run(cmd)
})
Context("Operator", func() {
It("should run successfully", func() {
var controllerPodName string
var err error
// projectimage stores the name of the image used in the example
projectimage := "example.com/plugin-barman-cloud:v0.0.1"
By("building the manager(Operator) image")
//nolint:gosec,perfsprint
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage))
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("loading the manager(Operator) image on Kind")
err = utils.LoadImageToKindClusterWithName(projectimage)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("installing CRDs")
cmd = exec.Command("make", "install")
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("deploying the controller-manager")
//nolint:gosec,perfsprint
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage))
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("validating that the controller-manager pod is running as expected")
verifyControllerUp := func() error {
// Get pod name
cmd = exec.Command("kubectl", "get",
"pods", "-l", "control-plane=controller-manager",
"-o", "go-template={{ range .items }}"+
"{{ if not .metadata.deletionTimestamp }}"+
"{{ .metadata.name }}"+
"{{ \"\\n\" }}{{ end }}{{ end }}",
"-n", namespace,
)
podOutput, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
podNames := utils.GetNonEmptyLines(string(podOutput))
if len(podNames) != 1 {
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
}
controllerPodName = podNames[0]
ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager"))
// Validate pod status
cmd = exec.Command("kubectl", "get",
"pods", controllerPodName, "-o", "jsonpath={.status.phase}",
"-n", namespace,
)
status, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
if string(status) != "Running" {
return fmt.Errorf("controller pod in %s status", status)
}
return nil
}
EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed())
})
}) })
}) })

View File

@ -0,0 +1,106 @@
/*
Copyright 2024.
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 certmanager
import (
"context"
"fmt"
"time"
types2 "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/kustomize/api/types"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/deployment"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/kustomize"
)
// InstallOptions contains the options for installing cert-manager
type InstallOptions struct {
Version string
IgnoreExistResources bool
}
// InstallOption is a function that sets up an option for installing cert-manager
type InstallOption func(*InstallOptions)
// WithVersion sets the version of cert-manager to install
func WithVersion(version string) InstallOption {
return func(opts *InstallOptions) {
opts.Version = version
}
}
// WithIgnoreExistingResources sets whether to ignore existing resources
func WithIgnoreExistingResources(ignore bool) InstallOption {
return func(opts *InstallOptions) {
opts.IgnoreExistResources = ignore
}
}
// TODO: renovate
// DefaultVersion is the default version of cert-manager to install
const DefaultVersion = "v1.15.1"
// Install installs cert-manager using kubectl
func Install(ctx context.Context, cl client.Client, opts ...InstallOption) error {
options := &InstallOptions{
Version: DefaultVersion,
IgnoreExistResources: true,
}
for _, opt := range opts {
opt(options)
}
// Define the KustomizationResourceURL for the cert-manager manifests
url := fmt.Sprintf("https://github.com/cert-manager/cert-manager/releases/download/%s/cert-manager.yaml",
options.Version)
// Generate the Kustomization
kustomization := &types.Kustomization{
Resources: []string{url},
}
// Add all the resources defined in the cert-manager manifests
if err := kustomize.ApplyKustomization(ctx, cl, kustomization); err != nil {
return fmt.Errorf("failed to apply kustomization: %w", err)
}
// Set default timeout if none is provided
const defaultTimeout = 5 * time.Minute
if _, ok := ctx.Deadline(); !ok {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, defaultTimeout)
defer cancel()
}
deployments := []string{"cert-manager", "cert-manager-cainjector", "cert-manager-webhook"}
interval := 5 * time.Second
for _, deploymentName := range deployments {
if err := deployment.WaitForDeploymentReady(ctx, cl, types2.NamespacedName{
Namespace: "cert-manager",
Name: deploymentName,
}, interval); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2024.
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 certmanager provides utilities for setting up and managing
// cert-manager for end-to-end testing.
package certmanager

View File

@ -0,0 +1,153 @@
/*
Copyright 2024.
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 cloudnativepg
import (
"context"
"fmt"
"time"
types2 "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/resid"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/deployment"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/kustomize"
)
// InstallCloudNativePGOptions contains the options for installing CloudNativePG
type InstallCloudNativePGOptions struct {
ImageName string
ImageTag string
KustomizationResourceURL string
KustomizationRef string
KustomizationTimeout string
IgnoreExistResources bool
}
// InstallOption is a function that sets up an option for installing CloudNativePG
type InstallOption func(*InstallCloudNativePGOptions)
// WithImageName sets the name for the CloudNativePG image
func WithImageName(ref string) InstallOption {
return func(opts *InstallCloudNativePGOptions) {
opts.ImageName = ref
}
}
// WithImageTag sets the tag for the CloudNativePG image
func WithImageTag(tag string) InstallOption {
return func(opts *InstallCloudNativePGOptions) {
opts.ImageTag = tag
}
}
// WithKustomizationResourceURL sets the URL for the CloudNativePG kustomization
func WithKustomizationResourceURL(url string) InstallOption {
return func(opts *InstallCloudNativePGOptions) {
opts.KustomizationResourceURL = url
}
}
// WithKustomizationRef sets the ref for the CloudNativePG kustomization
func WithKustomizationRef(ref string) InstallOption {
return func(opts *InstallCloudNativePGOptions) {
opts.KustomizationRef = ref
}
}
// WithKustomizationTimeout sets the timeout for the kustomization resources
func WithKustomizationTimeout(timeout string) InstallOption {
return func(opts *InstallCloudNativePGOptions) {
opts.KustomizationTimeout = timeout
}
}
// WithIgnoreExistingResources sets whether to ignore existing resources
func WithIgnoreExistingResources(ignore bool) InstallOption {
return func(opts *InstallCloudNativePGOptions) {
opts.IgnoreExistResources = ignore
}
}
// Install installs CloudNativePG using kubectl
func Install(ctx context.Context, cl client.Client, opts ...InstallOption) error {
// Defining the default options
options := &InstallCloudNativePGOptions{
ImageName: "ghcr.io/cloudnative-pg/cloudnative-pg-testing",
ImageTag: "main",
KustomizationResourceURL: "https://github.com/cloudnative-pg/cloudnative-pg.git/config/default",
KustomizationRef: "main",
KustomizationTimeout: "120",
IgnoreExistResources: true,
}
for _, opt := range opts {
opt(options)
}
kustomizationFullURL := fmt.Sprintf("%s/?ref=%s&timeout=%s", options.KustomizationResourceURL,
options.KustomizationRef, options.KustomizationTimeout)
// Generate the Kustomization
kustomization := &types.Kustomization{
Resources: []string{kustomizationFullURL},
Images: []types.Image{
{
Name: "controller",
NewName: options.ImageName,
NewTag: options.ImageTag,
},
},
Patches: []types.Patch{
{
Patch: fmt.Sprintf(`[{"op": "replace", "path": "/spec/template/spec/containers/0/env/0/value", "value": "%v:%v"}]`,
options.ImageName, options.ImageTag),
Target: &types.Selector{
ResId: resid.ResId{
Gvk: resid.Gvk{Kind: "Deployment", Version: "v1", Group: "apps"},
Name: "cnpg-controller-manager",
Namespace: "cnpg-system",
},
},
Options: nil,
},
},
}
if err := kustomize.ApplyKustomization(ctx, cl, kustomization); err != nil {
return fmt.Errorf("failed to apply kustomization: %w", err)
}
// Set default timeout if none is provided
const defaultTimeout = 5 * time.Minute
if _, ok := ctx.Deadline(); !ok {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, defaultTimeout)
defer cancel()
}
if err := deployment.WaitForDeploymentReady(ctx, cl, types2.NamespacedName{
Namespace: "cnpg-system",
Name: "cnpg-controller-manager",
}, 5*time.Second); err != nil {
return fmt.Errorf("failed to wait for deployment to be ready: %w", err)
}
return nil
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2024.
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 cloudnativepg provides utilities for setting up and managing
// CloudNativePG environments for end-to-end testing.
package cloudnativepg

View File

@ -0,0 +1,69 @@
/*
Copyright 2024.
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 deployment
import (
"context"
"fmt"
"time"
appsv1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// IsReady checks if the deployment is ready.
func IsReady(ctx context.Context, cl client.Client, name types.NamespacedName) (bool, error) {
deployment := &appsv1.Deployment{}
err := cl.Get(ctx, name, deployment)
if err != nil {
return false, fmt.Errorf("failed to get %s deployment: %w", name, err)
}
// Check if the deployment is ready
ready := false
for _, condition := range deployment.Status.Conditions {
if condition.Type == appsv1.DeploymentAvailable && condition.Status == "True" {
ready = true
break
}
}
if !ready {
return false, nil
}
return true, nil
}
// WaitForDeploymentReady waits for the deployment to be ready. ctx should have a timeout set.
func WaitForDeploymentReady(
ctx context.Context, cl client.Client, namespacedName types.NamespacedName, interval time.Duration,
) error {
return wait.PollUntilContextCancel(ctx, interval, false,
func(ctx context.Context) (bool, error) {
ready, err := IsReady(ctx, cl, namespacedName)
if err != nil {
return false, fmt.Errorf("failed to check if %s is ready: %w", namespacedName, err)
}
if ready {
return true, nil
}
return false, nil
})
}

View File

@ -0,0 +1,18 @@
/*
Copyright 2024.
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 deployment provides utilities for managing Kubernetes deployments
package deployment

View File

@ -0,0 +1,18 @@
/*
Copyright 2024.
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 e2etestenv provides a test environment for end-to-end tests.
package e2etestenv

View File

@ -0,0 +1,272 @@
/*
Copyright 2024.
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 e2etestenv
import (
"context"
"fmt"
"strings"
"time"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/certmanager"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/cloudnativepg"
"github.com/cloudnative-pg/plugin-barman-cloud/test/e2e/internal/kind"
)
// SetupOptions contains the options for setting up the test environment.
type SetupOptions struct {
K8sVersion string
KindVersion string
KindClusterNamePrefix string
KindAdditionalNetworks []string
CNPGKustomizationURL string
CNPGKustomizationRef string
CNPGKustomizationTimeout string
CNPGImageName string
CNPGImageTag string
CertManagerVersion string
IgnoreExistingResources bool
}
// SetupOption is a function that sets up an option for the test environment setup.
type SetupOption func(*SetupOptions)
// WithK8sVersion sets the Kubernetes version for the test environment.
func WithK8sVersion(version string) SetupOption {
return func(opts *SetupOptions) {
opts.K8sVersion = version
}
}
// WithKindVersion sets the Kind version for the test environment.
func WithKindVersion(version string) SetupOption {
return func(opts *SetupOptions) {
opts.KindVersion = version
}
}
// WithKindAdditionalNetworks sets the additional networks for the Kind cluster for the test environment.
func WithKindAdditionalNetworks(networks []string) SetupOption {
return func(opts *SetupOptions) {
opts.KindAdditionalNetworks = networks
}
}
// WithCNPGKustomizationURL sets the CloudNativePG kustomization URL for the test environment.
func WithCNPGKustomizationURL(url string) SetupOption {
return func(opts *SetupOptions) {
opts.CNPGKustomizationURL = url
}
}
// WithCNPGKustomizationRef sets the CloudNativePG kustomization ref for the test environment.
func WithCNPGKustomizationRef(ref string) SetupOption {
return func(opts *SetupOptions) {
opts.CNPGKustomizationRef = ref
}
}
// WithCNPGKustomizationTimeout sets the CloudNativePG kustomization timeout for the test environment.
func WithCNPGKustomizationTimeout(timeout string) SetupOption {
return func(opts *SetupOptions) {
opts.CNPGKustomizationTimeout = timeout
}
}
// WithCNPGImageName sets the CloudNativePG image name for the test environment.
func WithCNPGImageName(name string) SetupOption {
return func(opts *SetupOptions) {
opts.CNPGImageName = name
}
}
// WithCNPGImageTag sets the CloudNativePG image tag for the test environment.
func WithCNPGImageTag(tag string) SetupOption {
return func(opts *SetupOptions) {
opts.CNPGImageTag = tag
}
}
// WithCertManagerVersion sets the cert-manager version for the test environment.
func WithCertManagerVersion(version string) SetupOption {
return func(opts *SetupOptions) {
opts.CertManagerVersion = version
}
}
// WithIgnoreExistingResources sets the option to ignore existing resources when creating the test environment,
// instead of returning an error.
func WithIgnoreExistingResources(ignore bool) SetupOption {
return func(opts *SetupOptions) {
opts.IgnoreExistingResources = ignore
}
}
// WithKindClusterNamePrefix sets the prefix for the Kind cluster name for the test environment.
func withKindClusterNamePrefix(name string) SetupOption {
return func(opts *SetupOptions) {
opts.KindClusterNamePrefix = name
}
}
const (
kindConfigFile = "config/kind-config.yaml"
)
func defaultSetupOptions() SetupOptions {
// TODO: renovate
return SetupOptions{
K8sVersion: "v1.31.1",
KindVersion: "v0.24.0",
CertManagerVersion: "v1.15.1",
KindClusterNamePrefix: "e2e",
KindAdditionalNetworks: []string{},
}
}
// Setup sets up the test environment for the e2e tests, starting kind and installing the necessary components.
func Setup(ctx context.Context, opts ...SetupOption) (client.Client, error) {
options := defaultSetupOptions()
for _, opt := range opts {
opt(&options)
}
if err := setupKind(options); err != nil {
return nil, err
}
cl, err := getClient()
if err != nil {
return nil, err
}
if err := installCertManager(ctx, cl, options); err != nil {
return nil, err
}
if err := installCNPG(ctx, cl, options); err != nil {
return nil, err
}
// Return the Kubernetes client used for the tests
return cl, nil
}
func installCNPG(ctx context.Context, cl client.Client, options SetupOptions) error {
// Install CloudNativePG
var cnpgIstallOptions []cloudnativepg.InstallOption
if options.CNPGKustomizationURL != "" {
cnpgIstallOptions = append(cnpgIstallOptions,
cloudnativepg.WithKustomizationResourceURL(options.CNPGKustomizationURL))
}
if options.CNPGKustomizationRef != "" {
cnpgIstallOptions = append(cnpgIstallOptions, cloudnativepg.WithKustomizationRef(options.CNPGKustomizationRef))
}
if options.CNPGKustomizationTimeout != "" {
cnpgIstallOptions = append(cnpgIstallOptions,
cloudnativepg.WithKustomizationTimeout(options.CNPGKustomizationTimeout))
}
if options.CNPGImageName != "" {
cnpgIstallOptions = append(cnpgIstallOptions, cloudnativepg.WithImageName(options.CNPGImageName))
}
if options.CNPGImageTag != "" {
cnpgIstallOptions = append(cnpgIstallOptions, cloudnativepg.WithImageTag(options.CNPGImageTag))
}
if options.IgnoreExistingResources {
cnpgIstallOptions = append(cnpgIstallOptions,
cloudnativepg.WithIgnoreExistingResources(options.IgnoreExistingResources))
}
if err := cloudnativepg.Install(ctx, cl, cnpgIstallOptions...); err != nil {
return fmt.Errorf("failed to install cloudnative-pg: %w", err)
}
return nil
}
func installCertManager(ctx context.Context, cl client.Client, options SetupOptions) error {
// Install cert-manager
var certManagerInstallOptions []certmanager.InstallOption
if options.CertManagerVersion != "" {
certManagerInstallOptions = append(certManagerInstallOptions,
certmanager.WithVersion(options.CertManagerVersion))
}
if options.IgnoreExistingResources {
certManagerInstallOptions = append(certManagerInstallOptions,
certmanager.WithIgnoreExistingResources(options.IgnoreExistingResources))
}
cmCtx, cmCtxCancel := context.WithTimeout(ctx, 2*time.Minute)
defer cmCtxCancel()
if err := certmanager.Install(cmCtx, cl,
certManagerInstallOptions...); err != nil {
return fmt.Errorf("failed to install cert-manager: %w", err)
}
return nil
}
func getClient() (client.Client, error) {
// Use the current kubernetes client configuration
cfg, err := config.GetConfig()
if err != nil {
return nil, fmt.Errorf("failed to get Kubernetes config: %w", err)
}
cl, err := client.New(cfg, client.Options{})
if err != nil {
return nil, fmt.Errorf("failed to create Kubernetes client: %w", err)
}
return cl, nil
}
func setupKind(options SetupOptions) error {
// This function sets up the environment for the e2e tests
// by creating the cluster and installing the necessary
// components.
if err := kind.EnsureVersion(options.KindVersion); err != nil {
return fmt.Errorf("failed to ensure Kind kindVersion: %w", err)
}
expectedClusterName := kindClusterName(options.KindClusterNamePrefix, options.K8sVersion)
clusterIsRunning, err := kind.IsClusterRunning(expectedClusterName)
if err != nil {
return fmt.Errorf("failed to check if Kind cluster is running: %w", err)
}
if !clusterIsRunning {
kindOpts := []kind.CreateClusterOption{
kind.WithK8sVersion(options.K8sVersion),
kind.WithConfigFile(kindConfigFile),
kind.WithNetworks(options.KindAdditionalNetworks),
}
if err := kind.CreateCluster(expectedClusterName, kindOpts...); err != nil {
return fmt.Errorf("failed to create Kind cluster: %w", err)
}
}
return nil
}
func kindClusterName(prefix, k8sVersion string) string {
k8sVersion = strings.ReplaceAll(k8sVersion, ".", "-")
return fmt.Sprintf("%s-%s", prefix, k8sVersion)
}

View File

@ -0,0 +1,133 @@
/*
Copyright 2024.
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 kind
import (
"fmt"
"os"
"os/exec"
"strings"
)
// IsClusterRunning checks if a Kind cluster with the given name is running
func IsClusterRunning(clusterName string) (bool, error) {
cmd := exec.Command(Kind, "get", "clusters")
output, err := cmd.CombinedOutput()
if err != nil {
return false, fmt.Errorf("failed to get Kind clusters: %w, output: %s", err, string(output))
}
clusters := strings.Split(strings.TrimSpace(string(output)), "\n")
for _, cluster := range clusters {
if cluster == clusterName {
return true, nil
}
}
return false, nil
}
// CreateClusterOptions are the options for creating a Kind cluster
type CreateClusterOptions struct {
ConfigFile string
K8sVersion string
Networks []string
}
// CreateClusterOption is the option for creating a Kind cluster
type CreateClusterOption func(*CreateClusterOptions)
// WithConfigFile sets the config file for creating a Kind cluster
func WithConfigFile(configFile string) CreateClusterOption {
return func(opts *CreateClusterOptions) {
opts.ConfigFile = configFile
}
}
// WithK8sVersion sets the Kubernetes version for creating a Kind cluster
func WithK8sVersion(k8sVersion string) CreateClusterOption {
return func(opts *CreateClusterOptions) {
opts.K8sVersion = k8sVersion
}
}
// WithNetwork sets the network for creating a Kind cluster
func WithNetworks(networks []string) CreateClusterOption {
return func(opts *CreateClusterOptions) {
opts.Networks = networks
}
}
// CreateCluster creates a Kind cluster with the given name
func CreateCluster(name string, opts ...CreateClusterOption) error {
options := &CreateClusterOptions{}
for _, opt := range opts {
opt(options)
}
args := []string{"create", "cluster", "--name", name}
if options.ConfigFile != "" {
args = append(args, "--config", options.ConfigFile)
}
if options.K8sVersion != "" {
args = append(args, "--image", fmt.Sprintf("kindest/node:%s", options.K8sVersion))
}
cmd := exec.Command(Kind, args...) // #nosec
cmd.Dir, _ = os.Getwd()
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("'kind create cluster' failed: %w, output: %s", err, string(output))
}
// Since a cluster can mount additional certificates, we need to make sure they are
// usable by the nodes in the cluster.
nodes, err := getNodes(name)
if err != nil {
return err
}
for _, node := range nodes {
cmd = exec.Command("docker", "exec", node, "update-ca-certificates") // #nosec
output, err = cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to update CA certificates in node %s: %w, output: %s", node, err, string(output))
}
}
for _, network := range options.Networks {
for _, node := range nodes {
cmd = exec.Command("docker", "network", "connect", network, node) // #nosec
output, err = cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to connect node %s to network %s: %w, output: %s", node, network, err,
string(output))
}
}
}
return nil
}
func getNodes(clusterName string) ([]string, error) {
cmd := exec.Command(Kind, "get", "nodes", "--name", clusterName)
output, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("failed to get Kind nodes: %w, output: %s", err, string(output))
}
return strings.Split(strings.TrimSpace(string(output)), "\n"), nil
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2024.
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 kind provides utilities for ensuring the presence and correct version of the Kind binary,
// as well as functions for installing and managing the Kind binary in a local project.
package kind

View File

@ -0,0 +1,116 @@
/*
Copyright 2024.
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 kind
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
)
// Kind is the name of the Kind binary
const Kind = "kind"
// EnsureVersion ensures that there is a Kind binary, is at the correct version, and is in the PATH
func EnsureVersion(requiredVersion string) error {
if _, err := exec.LookPath(Kind); err == nil {
version, err := Version()
if err != nil {
return err
}
if strings.Contains(version, requiredVersion) {
return nil
}
}
return Install(requiredVersion)
}
// InstallOptions are the options for installing the Kind binary
type InstallOptions struct {
BinDir string
}
// InstallOption is the option for installing the Kind binary
type InstallOption func(*InstallOptions)
// WithBinDir sets the directory to install the Kind binary
func WithBinDir(binDir string) InstallOption {
return func(opts *InstallOptions) {
opts.BinDir = binDir
}
}
// Install installs the Kind binary in the local project's /bin directory
func Install(version string, opts ...InstallOption) error {
options := &InstallOptions{
BinDir: filepath.Join(".", "bin"), // default bin directory
}
for _, opt := range opts {
opt(options)
}
// Get BinDir absolute path
absBinDir, err := filepath.Abs(options.BinDir)
if err != nil {
return fmt.Errorf("failed to get absolute path for bin directory: %w", err)
}
options.BinDir = absBinDir
// Ensure the /bin directory exists
if err := os.MkdirAll(options.BinDir, os.ModeDir); err != nil {
return fmt.Errorf("failed to create bin directory: %w", err)
}
// Determine the OS and architecture
osName := runtime.GOOS
arch := runtime.GOARCH
// Download the Kind binary
url := fmt.Sprintf("https://github.com/kubernetes-sigs/kind/releases/download/%s/kind-%s-%s", version, osName, arch)
binaryPath := filepath.Join(options.BinDir, Kind)
cmd := exec.Command("curl", "-Lo", binaryPath, url) // #nosec
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to download Kind binary: %w, output: %s", err, string(output))
}
// Make the Kind binary executable
cmd = exec.Command("chmod", "+x", binaryPath) // #nosec
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to make Kind binary executable: %w, output: %s", err, string(output))
}
if err := os.Setenv("PATH", fmt.Sprintf("%s:%s", options.BinDir, os.Getenv("PATH"))); err != nil {
return fmt.Errorf("failed to set PATH: %w", err)
}
return nil
}
// Version returns the current version of the Kind binary
func Version() (string, error) {
cmd := exec.Command(Kind, "version")
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("failed to get Kind version: %w, output: %s", err, string(output))
}
version := strings.TrimSpace(string(output))
return version, nil
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2024.
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 kustomize provides utilities for applying and managing Kubernetes
// customizations using Kustomize.
package kustomize

View File

@ -0,0 +1,139 @@
/*
Copyright 2024.
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 kustomize
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"log"
"gopkg.in/yaml.v3"
apimachineryerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
// ApplyKustomizationOptions holds options for applying kustomizations
type ApplyKustomizationOptions struct {
IgnoreExistingResources bool
}
// ApplyKustomizationOption is a functional option for ApplyKustomization
type ApplyKustomizationOption func(*ApplyKustomizationOptions)
// ApplyKustomization builds the kustomization and creates the resources
func ApplyKustomization(
ctx context.Context,
cl client.Client,
kustomization *types.Kustomization,
options ...ApplyKustomizationOption,
) error {
opts := &ApplyKustomizationOptions{
IgnoreExistingResources: true,
}
for _, opt := range options {
opt(opts)
}
// We'd rather use an in-memory filesystem, but krusty doesn't support it yet for git URLs
// See https://github.com/kubernetes-sigs/kustomize/issues/4390
// Create an in-memory filesystem
fSys := filesys.MakeFsOnDisk()
// Write the Kustomization to the filesystem
kustomizationYAML, err := yaml.Marshal(kustomization)
if err != nil {
return fmt.Errorf("failed to marshal kustomization: %w", err)
}
err = fSys.WriteFile("kustomization.yaml", kustomizationYAML)
if err != nil {
return fmt.Errorf("failed to write kustomization.yaml: %w", err)
}
defer fSys.RemoveAll("kustomization.yaml") //nolint:errcheck
// Build the Kustomization
k := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
resourceMap, err := k.Run(fSys, ".")
if err != nil {
return fmt.Errorf("failed to run kustomize: %w", err)
}
return applyResourceMap(ctx, cl, resourceMap)
}
func applyResourceMap(ctx context.Context, cl client.Client, resourceMap resmap.ResMap) error {
yamlBytes, err := resourceMap.AsYaml()
if err != nil {
return fmt.Errorf("failed to convert resources to YAML: %w", err)
}
r := bytes.NewReader(yamlBytes)
dec := yaml.NewDecoder(r)
for {
// parse the YAML doc
obj := &unstructured.Unstructured{Object: map[string]interface{}{}}
err := dec.Decode(obj.Object)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return fmt.Errorf("could not decode object: %w", err)
}
if obj.Object == nil {
continue
}
if err := applyResource(ctx, cl, obj); err != nil {
return err
}
}
return nil
}
func applyResource(ctx context.Context, cl client.Client, obj *unstructured.Unstructured) error {
if err := cl.Create(ctx, obj); err != nil {
if apimachineryerrors.IsAlreadyExists(err) {
// If the resource already exists, retrieve the existing resource
existing := &unstructured.Unstructured{}
existing.SetGroupVersionKind(obj.GroupVersionKind())
key := client.ObjectKey{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
if err := cl.Get(ctx, key, existing); err != nil {
log.Fatalf("Error getting existing resource: %v", err)
}
// Update the existing resource with the new data
obj.SetResourceVersion(existing.GetResourceVersion())
err = cl.Update(ctx, obj)
if err != nil {
return fmt.Errorf("error updating resource: %v", err)
}
} else {
return fmt.Errorf("error creating resource: %v", err)
}
}
return nil
}

1
test/e2e/kustomize/config Symbolic link
View File

@ -0,0 +1 @@
../../../config/

View File

@ -0,0 +1 @@
../../../kubernetes/

View File

@ -1,144 +0,0 @@
/*
Copyright 2024.
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 utils
import (
"fmt"
"os"
"os/exec"
"strings"
. "github.com/onsi/ginkgo/v2"
)
const (
prometheusOperatorVersion = "v0.72.0"
prometheusOperatorURL = "https://github.com/prometheus-operator/prometheus-operator/" +
"releases/download/%s/bundle.yaml"
certmanagerVersion = "v1.14.4"
certmanagerURLTmpl = "https://github.com/jetstack/cert-manager/releases/download/%s/cert-manager.yaml"
)
func warnError(err error) {
_, _ = fmt.Fprintf(GinkgoWriter, "warning: %v\n", err)
}
// InstallPrometheusOperator installs the prometheus Operator to be used to export the enabled metrics.
func InstallPrometheusOperator() error {
url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion)
cmd := exec.Command("kubectl", "create", "-f", url)
_, err := Run(cmd)
return err
}
// Run executes the provided command within this context.
func Run(cmd *exec.Cmd) ([]byte, error) {
dir, _ := GetProjectDir()
cmd.Dir = dir
if err := os.Chdir(cmd.Dir); err != nil {
_, _ = fmt.Fprintf(GinkgoWriter, "chdir dir: %s\n", err)
}
cmd.Env = append(os.Environ(), "GO111MODULE=on")
command := strings.Join(cmd.Args, " ")
_, _ = fmt.Fprintf(GinkgoWriter, "running: %s\n", command)
output, err := cmd.CombinedOutput()
if err != nil {
return output, fmt.Errorf("%s failed with error: (%w) %s", command, err, string(output))
}
return output, nil
}
// UninstallPrometheusOperator uninstalls the prometheus.
func UninstallPrometheusOperator() {
url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion)
cmd := exec.Command("kubectl", "delete", "-f", url)
if _, err := Run(cmd); err != nil {
warnError(err)
}
}
// UninstallCertManager uninstalls the cert manager.
func UninstallCertManager() {
url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion)
cmd := exec.Command("kubectl", "delete", "-f", url)
if _, err := Run(cmd); err != nil {
warnError(err)
}
}
// InstallCertManager installs the cert manager bundle.
func InstallCertManager() error {
url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion)
cmd := exec.Command("kubectl", "apply", "-f", url)
if _, err := Run(cmd); err != nil {
return err
}
// Wait for cert-manager-webhook to be ready, which can take time if cert-manager
// was re-installed after uninstalling on a cluster.
cmd = exec.Command("kubectl", "wait", "deployment.apps/cert-manager-webhook",
"--for", "condition=Available",
"--namespace", "cert-manager",
"--timeout", "5m",
)
_, err := Run(cmd)
return err
}
// LoadImageToKindClusterWithName loads a local docker image to the kind cluster.
func LoadImageToKindClusterWithName(name string) error {
cluster := "kind"
if v, ok := os.LookupEnv("KIND_CLUSTER"); ok {
cluster = v
}
kindOptions := []string{"load", "docker-image", name, "--name", cluster}
cmd := exec.Command("kind", kindOptions...)
_, err := Run(cmd)
return err
}
// GetNonEmptyLines converts given command output string into individual objects
// according to line breakers, and ignores the empty elements in it.
func GetNonEmptyLines(output string) []string {
var res []string
elements := strings.Split(output, "\n")
for _, element := range elements {
if element != "" {
res = append(res, element)
}
}
return res
}
// GetProjectDir will return the directory where the project is.
func GetProjectDir() (string, error) {
wd, err := os.Getwd()
if err != nil {
return wd, fmt.Errorf("failed to get the current working directory: %w", err)
}
wd = strings.ReplaceAll(wd, "/test/e2e", "")
return wd, nil
}