From aa3fd733817a7b0d971b5d4adfe1f710f99d7f49 Mon Sep 17 00:00:00 2001 From: Tyler Gillson Date: Mon, 15 Jul 2024 12:20:22 -0600 Subject: [PATCH] feat: air-gapped support with hauler (#74) ## Description - use OCI client instead of Helm client due to https://github.com/helm/helm/issues/12810 - prompt user for Hauler configuration for air-gapped installs & customize image and chart endpoints accordingly - reinstate advanced kind config that was inexplicably removed - fix containerdConfigPatches for insecure registries in kind cluster template - bump kindest/node image - bump kube-rbac-proxy images Requires: - https://github.com/validator-labs/validator/pull/322 --------- Signed-off-by: Tyler Gillson Co-authored-by: Ahmad Malik Ibrahim --- build | 2 +- cmd/root.go | 2 +- go.mod | 47 +++++- go.sum | 118 ++++++++++++-- pkg/cmd/validator/validator.go | 33 ++-- pkg/components/network.go | 3 +- pkg/components/oci.go | 3 +- pkg/components/validator.go | 22 ++- pkg/components/vsphere.go | 3 +- pkg/config/constants.go | 24 ++- pkg/services/env_service.go | 144 ++++++++++++++++-- pkg/services/validator/aws.go | 3 + pkg/services/validator/aws_test.go | 3 + pkg/services/validator/azure.go | 3 + pkg/services/validator/common.go | 23 ++- pkg/services/validator/network.go | 1 + pkg/services/validator/network_test.go | 3 + pkg/services/validator/oci.go | 3 + pkg/services/validator/validator_service.go | 50 ++++-- pkg/services/validator/vmware.go | 98 ++++++++---- pkg/services/validator/vmware_test.go | 3 + .../resources/kind/cluster-configuration.tmpl | 26 ++-- .../validator/validator-base-values.tmpl | 2 +- .../validator-plugin-aws-values.tmpl | 2 +- .../validator-plugin-network-values.tmpl | 2 +- .../validator-plugin-vsphere-values.tmpl | 2 +- pkg/utils/kind/kind.go | 50 ++++-- pkg/utils/kind/kind_test.go | 22 +-- pkg/utils/network/network.go | 59 +++++++ .../_validator/testcases/data/validator.yaml | 6 + .../_validator/testcases/test_validator.go | 3 + tests/unit-test-data/kindconfig-basic.yaml | 2 +- .../unit-test-data/kindconfig-shared-ca.yaml | 2 +- 33 files changed, 623 insertions(+), 146 deletions(-) create mode 100644 pkg/utils/network/network.go diff --git a/build b/build index 0d69f881..866b77ca 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 0d69f881c960769f240d7a76478527c6622df63a +Subproject commit 866b77ca18f2115062f185d3c536b93075b883ff diff --git a/cmd/root.go b/cmd/root.go index 4f75a1e4..9b9f186d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -97,7 +97,7 @@ func InitConfig() { // If a config file is found, read it if err := viper.ReadInConfig(); err == nil { viper.OnConfigChange(func(e fsnotify.Event) { - fmt.Println("Config file changed:", e.Name) + log.Debug("Config file changed: %s", e.Name) // This is actually a noop - the updated config will be // written to disk separately, but still nice to notify // the user that something changed! diff --git a/go.mod b/go.mod index 9f2eca3e..e371dcf6 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/spectrocloud-labs/prompts-tui v0.0.0-20240621222805-66ae32c882c2 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 - github.com/validator-labs/validator v0.0.43 + github.com/validator-labs/validator v0.0.46-0.20240712145341-827d477b7678 github.com/validator-labs/validator-plugin-aws v0.1.1 github.com/validator-labs/validator-plugin-azure v0.0.12 github.com/validator-labs/validator-plugin-network v0.0.17 @@ -35,17 +35,49 @@ require ( atomicgo.dev/cursor v0.2.0 // indirect atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/schedule v0.1.0 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.29 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/BurntSushi/toml v1.4.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.30.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.24 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.24 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.30.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 // indirect + github.com/aws/smithy-go v1.20.3 // indirect + github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240708141356-efa334f881fc // indirect + github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect github.com/containerd/console v1.0.4 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/docker/cli v24.0.7+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect + github.com/docker/docker v24.0.7+incompatible // indirect + github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -53,9 +85,11 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-containerregistry v0.20.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/gookit/color v1.5.4 // indirect github.com/hashicorp/go-version v1.7.0 // indirect @@ -63,8 +97,10 @@ require ( github.com/huandu/xstrings v1.5.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/kr/text v0.2.0 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -73,11 +109,14 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/zerolog v1.28.0 // indirect @@ -89,11 +128,13 @@ require ( github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/vbatts/tar-split v0.11.5 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.25.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect @@ -106,7 +147,7 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a // indirect k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect - sigs.k8s.io/cluster-api v1.7.3 // indirect + sigs.k8s.io/cluster-api v1.7.4 // indirect sigs.k8s.io/controller-runtime v0.18.4 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect diff --git a/go.sum b/go.sum index 3d97d933..76cae5aa 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,35 @@ atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= emperror.dev/errors v0.8.1 h1:UavXZ5cSX/4u9iyvH6aDcuGkVjeexUGJ7Ij7G4VfQT0= emperror.dev/errors v0.8.1/go.mod h1:YcRvLPh626Ubn2xqtoprejnA5nFha+TJ+2vew48kWuE= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= +github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= +github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/L30Bola/aws-policy v0.0.0-20230126045340-5e6118545ac1 h1:3zcU9Ds6BHD3KnwbspH16kMGzLomnI2SNsCkq0i5avI= @@ -31,9 +58,45 @@ github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYr github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/aws/aws-sdk-go-v2 v1.30.1 h1:4y/5Dvfrhd1MxRDD77SrfsDaj8kUkkljU7XE83NPV+o= +github.com/aws/aws-sdk-go-v2 v1.30.1/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= +github.com/aws/aws-sdk-go-v2/config v1.27.24 h1:NM9XicZ5o1CBU/MZaHwFtimRpWx9ohAUAqkG6AqSqPo= +github.com/aws/aws-sdk-go-v2/config v1.27.24/go.mod h1:aXzi6QJTuQRVVusAO8/NxpdTeTyr/wRcybdDtfUwJSs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.24 h1:YclAsrnb1/GTQNt2nzv+756Iw4mF8AOzcDfweWwwm/M= +github.com/aws/aws-sdk-go-v2/credentials v1.17.24/go.mod h1:Hld7tmnAkoBQdTMNYZGzztzKRdA4fCdn9L83LOoigac= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 h1:Aznqksmd6Rfv2HQN9cpqIV/lQRMaIpJkLLaJ1ZI76no= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9/go.mod h1:WQr3MY7AxGNxaqAtsDWn+fBxmd4XvLkzeqQ8P1VM0/w= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 h1:5SAoZ4jYpGH4721ZNoS1znQrhOfZinOhc4XuTXx/nVc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13/go.mod h1:+rdA6ZLpaSeM7tSg/B0IEDinCIBJGmW8rKDFkYpP04g= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 h1:WIijqeaAO7TYFLbhsZmi2rgLEAtWOC1LhxCAVTJlSKw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13/go.mod h1:i+kbfa76PQbWw/ULoWnp51EYVWH4ENln76fLQE3lXT8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/service/ecr v1.30.1 h1:zV3FlyuyPzfyFOXKu6mJW9JBGzdtOgpdlj3va+naOD8= +github.com/aws/aws-sdk-go-v2/service/ecr v1.30.1/go.mod h1:l0zC7cSb2vAH1fr8+BRlolWT9cwlKpbRC8PjW6tyyIU= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1 h1:54/7zy+oA2ep9UzWjAtccawCj3ZAXhMXxwBg0yNRxTA= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1/go.mod h1:2UjSvHCwdRoPF17osaRvfBXuo32KPSvTlGMii5YbjyU= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 h1:I9zMeF107l0rJrpnHpjEiiTSCKYAIw8mALiXcPsGBiA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15/go.mod h1:9xWJ3Q/S6Ojusz1UIkfycgD1mGirJfLLKqq3LPT7WN8= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 h1:p1GahKIjyMDZtiKoIn0/jAj/TkMzfzndDv5+zi2Mhgc= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.1/go.mod h1:/vWdhoIoYA5hYoPZ6fm7Sv4d8701PiG5VKe8/pPJL60= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 h1:ORnrOK0C4WmYV/uYt3koHEWBLYsRDwk2Np+eEoyV4Z0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2/go.mod h1:xyFHA4zGxgYkdD73VeezHt3vSKEG9EmFnGwoKlP00u4= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 h1:+woJ607dllHJQtsnJLi52ycuqHMwlW+Wqm2Ppsfp4nQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.1/go.mod h1:jiNR3JqT15Dm+QWq2SRgh0x0bCNSRP2L25+CqPNpJlQ= +github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= +github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240708141356-efa334f881fc h1:i/hSTHoe0WO1I7N5BCyB3Ei6PDtOXn82e3YSs9W4F4Y= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240708141356-efa334f881fc/go.mod h1:vSzBu9U6tslAOAc0l7k5kx2ipWxrNezy0LZEWK3472A= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= +github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -43,14 +106,22 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= +github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= +github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= +github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02 h1:tR3jsKPiO/mb6ntzk/dJlHZtm37CPfVp1C9KIo534+4= github.com/dougm/pretty v0.0.0-20171025230240-2ee9d7453c02/go.mod h1:7NQ3kWOx2cZOSjtcveTa5nqupVr2s6/83sG+rTlI7uA= 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/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -59,8 +130,6 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= -github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -75,6 +144,10 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= @@ -82,6 +155,8 @@ github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1: github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.20.0 h1:wRqHpOeVh3DnenOrPy9xDOLdnLatiGuuNRVelR2gSbg= +github.com/google/go-containerregistry v0.20.0/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= 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/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -106,12 +181,18 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= @@ -143,6 +224,8 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -161,6 +244,10 @@ github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= 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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -224,13 +311,14 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/validator-labs/validator v0.0.43 h1:cFyV/gV1R5lhVpijlqZzE2Dz63fMo7Z8CAqXFxNpnd0= -github.com/validator-labs/validator v0.0.43/go.mod h1:cAlwTHNMNu5MUKh3qSa9EUSk2kUmWtzRY9tOrCylwpc= +github.com/validator-labs/validator v0.0.46-0.20240712145341-827d477b7678 h1:uqcFWickJxhpIp43Lsk42zWpEfhLpD0kQhFYW3p90sA= +github.com/validator-labs/validator v0.0.46-0.20240712145341-827d477b7678/go.mod h1:J351YCG6U/npAyoH0yJLKqSN1WqLx30A72Std6ME9p0= github.com/validator-labs/validator-plugin-aws v0.1.1 h1:GPWSk1hSRBV+NgOBKKn0q6f2iH3+ZikHYuSD6S41Ybk= github.com/validator-labs/validator-plugin-aws v0.1.1/go.mod h1:GGFVx01t77XomgrPZFmF5Dkre+iqmtBOBjThuWgB/jI= github.com/validator-labs/validator-plugin-azure v0.0.12 h1:zlsXvu/jud58aH9FA3I5U0haANbLLQe1N/gAf093LLg= @@ -241,6 +329,8 @@ github.com/validator-labs/validator-plugin-oci v0.0.10 h1:Qd6zgS9gN/RjZ+EV3z8LhC github.com/validator-labs/validator-plugin-oci v0.0.10/go.mod h1:QAFcEmXDGKId3gsbC3C2Kg4qWW71FLimi9VeGQtEp3Y= github.com/validator-labs/validator-plugin-vsphere v0.0.26 h1:Zoe75nhRo9duPAvptKotWnNDAukYHgPP+fMdVI8axz8= github.com/validator-labs/validator-plugin-vsphere v0.0.26/go.mod h1:wZFC9Td8AinrqFZA4mVUwmnWhe1ZG++B5zJ4OYAB3xw= +github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= +github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= github.com/vmware/govmomi v0.38.0 h1:UvQpLAOjDpO0JUxoPCXnEzOlEa/9kejO6K58qOFr6cM= github.com/vmware/govmomi v0.38.0/go.mod h1:mtGWtM+YhTADHlCgJBiskSRPOZRsN9MSjPzaZLte/oQ= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= @@ -253,13 +343,14 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= @@ -273,6 +364,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -285,12 +377,15 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -316,6 +411,7 @@ golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -356,6 +452,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws= @@ -372,8 +470,8 @@ k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a h1:zD1uj3Jf+mD4zmA7W+goE5 k8s.io/kube-openapi v0.0.0-20240521193020-835d969ad83a/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/cluster-api v1.7.3 h1:DsSRxsA+18jxLqPAo29abZ9kOPK1/xwhSuQb/MROzSs= -sigs.k8s.io/cluster-api v1.7.3/go.mod h1:V9ZhKLvQtsDODwjXOKgbitjyCmC71yMBwDcMyNNIov0= +sigs.k8s.io/cluster-api v1.7.4 h1:gT9WGbLXKE19pNR6s/cTLRqK2G0EbwxxQrUrw7/w5P4= +sigs.k8s.io/cluster-api v1.7.4/go.mod h1:V9ZhKLvQtsDODwjXOKgbitjyCmC71yMBwDcMyNNIov0= sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/pkg/cmd/validator/validator.go b/pkg/cmd/validator/validator.go index cb7aa34e..c1dd0841 100644 --- a/pkg/cmd/validator/validator.go +++ b/pkg/cmd/validator/validator.go @@ -23,6 +23,7 @@ import ( vapi "github.com/validator-labs/validator/api/v1alpha1" "github.com/validator-labs/validator/pkg/helm" + "github.com/validator-labs/validator/pkg/oci" "github.com/validator-labs/validatorctl/pkg/components" cfg "github.com/validator-labs/validatorctl/pkg/config" @@ -85,6 +86,7 @@ func DeployValidatorCommand(c *cfg.Config, tc *cfg.TaskConfig, reconfigure bool) // for dev build versions, we allow selection of specific validator and plugin versions // for all other builds, we set a fixed version for the validator and plugins vc.UseFixedVersions = !string_utils.IsDevVersion(tc.CliVersion) + if err := validator.ReadValidatorConfig(c, tc, vc); err != nil { return errors.Wrap(err, "failed to create new validator configuration") } @@ -494,7 +496,7 @@ func applyValidator(c *cfg.Config, vc *components.ValidatorConfig) error { "AzurePlugin": vc.AzurePlugin, } if vc.ProxyConfig.Enabled { - args["ProxyCaCertData"] = strings.Split(vc.ProxyConfig.Env.ProxyCaCertData, "\n") + args["ProxyCaCertData"] = strings.Split(vc.ProxyConfig.Env.ProxyCACert.Data, "\n") } values, err := embed_utils.RenderTemplateBytes(args, cfg.Validator, "validator-base-values.tmpl") @@ -536,8 +538,8 @@ func applyValidator(c *cfg.Config, vc *components.ValidatorConfig) error { opts := helm.Options{ Chart: vc.Release.Chart.Name, Repo: vc.Release.Chart.Repository, - CaFile: vc.Release.Chart.CaFile, - InsecureSkipTlsVerify: vc.Release.Chart.InsecureSkipTlsVerify, + CaFile: vc.Release.Chart.CAFile, + InsecureSkipTLSVerify: vc.Release.Chart.InsecureSkipTLSVerify, Version: vc.Release.Chart.Version, Values: finalValues, CreateNamespace: true, @@ -548,19 +550,26 @@ func applyValidator(c *cfg.Config, vc *components.ValidatorConfig) error { } var cleanupLocalChart bool - if strings.HasPrefix(opts.Repo, "oci://") { + if strings.HasPrefix(opts.Repo, oci.Scheme) { log.InfoCLI("\n==== Pulling validator Helm chart from OCI repository %s ====", opts.Repo) - opts.Untar = true - opts.UntarDir = c.RunLoc + opts.Path = fmt.Sprintf("%s/%s", c.RunLoc, opts.Chart) opts.Version = strings.TrimPrefix(opts.Version, "v") - if err := helmClient.Pull(opts); err != nil { - return err + ociClient := oci.NewOCIClient( + oci.WithMultiAuth(), + oci.WithTLSConfig(opts.InsecureSkipTLSVerify, opts.CaFile), + ) + ociOpts := oci.ImageOptions{ + Ref: fmt.Sprintf("%s/%s:%s", strings.TrimPrefix(opts.Repo, oci.Scheme), opts.Chart, opts.Version), + OutDir: opts.Path, + OutFile: opts.Chart, + } + if err := ociClient.PullChart(ociOpts); err != nil { + return fmt.Errorf("failed to pull Helm chart from OCI registry: %w", err) } - log.InfoCLI("Pulled plugin Helm chart %s from OCI repository", opts.Chart) - opts.Path = fmt.Sprintf("%s/%s", c.RunLoc, opts.Chart) + opts.Path = fmt.Sprintf("%s/%s.tgz", opts.Path, opts.Chart) opts.Chart = "" cleanupLocalChart = true log.InfoCLI("Reconfigured Helm options to deploy local chart") @@ -595,7 +604,7 @@ func applyValidator(c *cfg.Config, vc *components.ValidatorConfig) error { } // getHelmClient gets a helm client w/ a monkey-patched path to the embedded kind binary -func getHelmClient(vc *components.ValidatorConfig) (helm.HelmClient, error) { +func getHelmClient(vc *components.ValidatorConfig) (helm.Client, error) { apiCfg, err := kube.GetAPIConfig(vc.Kubeconfig) if err != nil { return nil, errors.Wrap(err, "failed to get API config from kubeconfig") @@ -693,7 +702,7 @@ func applyValidatorManifest(kubeconfig, name, path string) error { func createKindCluster(c *cfg.Config, vc *components.ValidatorConfig) error { clusterConfig := filepath.Join(c.RunLoc, "kind-cluster-config.yaml") - if err := kind.AdvancedConfig(vc.ProxyConfig.Env, clusterConfig); err != nil { + if err := kind.RenderKindConfig(vc.ProxyConfig.Env, vc.AirgapConfig.Hauler, clusterConfig); err != nil { return err } kindClusterName := vc.KindConfig.KindClusterName diff --git a/pkg/components/network.go b/pkg/components/network.go index d0c4940c..642cbc00 100644 --- a/pkg/components/network.go +++ b/pkg/components/network.go @@ -18,6 +18,7 @@ type NetworkConfig struct { // ConfigureNetworkPlugin configures the network plugin. func ConfigureNetworkPlugin(vc *ValidatorConfig, config NetworkConfig) { + // TODO: properly handle TLS, helm, and air-gap config vc.NetworkPlugin = &NetworkPluginConfig{ Enabled: true, Release: &vapi.HelmRelease{ @@ -25,7 +26,7 @@ func ConfigureNetworkPlugin(vc *ValidatorConfig, config NetworkConfig) { Name: cfg.ValidatorPluginNetwork, Repository: fmt.Sprintf("%s/%s", cfg.ValidatorHelmRepository, cfg.ValidatorPluginNetwork), Version: cfg.ValidatorChartVersions[cfg.ValidatorPluginNetwork], - InsecureSkipTlsVerify: true, + InsecureSkipTLSVerify: true, }, }, ReleaseSecret: &Secret{ diff --git a/pkg/components/oci.go b/pkg/components/oci.go index d2dc0eec..7b21c0c1 100644 --- a/pkg/components/oci.go +++ b/pkg/components/oci.go @@ -17,6 +17,7 @@ type OciConfig struct { // ConfigureOciPlugin configures the OCI plugin. func ConfigureOciPlugin(vc *ValidatorConfig, config OciConfig) { + // TODO: properly handle TLS, helm, and air-gap config vc.OCIPlugin = &OCIPluginConfig{ Enabled: true, Release: &vapi.HelmRelease{ @@ -24,7 +25,7 @@ func ConfigureOciPlugin(vc *ValidatorConfig, config OciConfig) { Name: cfg.ValidatorPluginOci, Repository: fmt.Sprintf("%s/%s", cfg.ValidatorHelmRepository, cfg.ValidatorPluginOci), Version: cfg.ValidatorChartVersions[cfg.ValidatorPluginOci], - InsecureSkipTlsVerify: true, + InsecureSkipTLSVerify: true, }, }, ReleaseSecret: &Secret{ diff --git a/pkg/components/validator.go b/pkg/components/validator.go index 665b4156..248c951c 100644 --- a/pkg/components/validator.go +++ b/pkg/components/validator.go @@ -28,6 +28,7 @@ type ValidatorConfig struct { ReleaseSecret *Secret `yaml:"helmReleaseSecret"` KindConfig KindConfig `yaml:"kindConfig"` Kubeconfig string `yaml:"kubeconfig"` + AirgapConfig *AirgapConfig `yaml:"airgapConfig"` SinkConfig *SinkConfig `yaml:"sinkConfig"` ProxyConfig *ProxyConfig `yaml:"proxyConfig"` ImageRegistry string `yaml:"imageRegistry"` @@ -49,9 +50,17 @@ func NewValidatorConfig() *ValidatorConfig { KindConfig: KindConfig{ UseKindCluster: false, }, + AirgapConfig: &AirgapConfig{ + Hauler: &env.Hauler{ + BasicAuth: &env.BasicAuth{}, + CACert: &env.CACert{}, + }, + }, SinkConfig: &SinkConfig{}, ProxyConfig: &ProxyConfig{ - Env: &env.Env{}, + Env: &env.Env{ + ProxyCACert: &env.CACert{}, + }, }, // Plugin config AWSPlugin: &AWSPluginConfig{ @@ -173,6 +182,12 @@ func (c *ValidatorConfig) encrypt() error { return nil } +// AirgapConfig represents the air-gapped configuration. +type AirgapConfig struct { + Enabled bool `yaml:"enabled"` + Hauler *env.Hauler `yaml:"hauler"` +} + // KindConfig represents the kind configuration. type KindConfig struct { UseKindCluster bool `yaml:"useKindCluster"` @@ -569,12 +584,13 @@ func SaveValidatorConfig(c *ValidatorConfig, tc *cfg.TaskConfig) error { // ConfigureBaseValidator configures the base validator configuration func ConfigureBaseValidator(vc *ValidatorConfig, kubeconfig string) { + // TODO: properly handle TLS, helm, and air-gap config vc.Release = &validator.HelmRelease{ Chart: validator.HelmChart{ Name: cfg.Validator, Repository: fmt.Sprintf("%s/%s", cfg.ValidatorHelmRepository, cfg.Validator), Version: cfg.ValidatorChartVersions[cfg.Validator], - InsecureSkipTlsVerify: true, + InsecureSkipTLSVerify: true, }, } vc.ReleaseSecret = &Secret{ @@ -582,7 +598,7 @@ func ConfigureBaseValidator(vc *ValidatorConfig, kubeconfig string) { } vc.KindConfig.UseKindCluster = true vc.Kubeconfig = kubeconfig - vc.ImageRegistry = cfg.ValidatorImageRegistry + vc.ImageRegistry = cfg.ValidatorImagePath() vc.ProxyConfig = &ProxyConfig{ Env: &env.Env{ PodCIDR: &cfg.DefaultPodCIDR, diff --git a/pkg/components/vsphere.go b/pkg/components/vsphere.go index ac82ab99..da91e920 100644 --- a/pkg/components/vsphere.go +++ b/pkg/components/vsphere.go @@ -25,6 +25,7 @@ type VsphereConfig struct { // ConfigureVspherePlugin configures the vSphere plugin. func ConfigureVspherePlugin(vc *ValidatorConfig, config VsphereConfig) { + // TODO: properly handle TLS, helm, and air-gap config vc.VspherePlugin = &VspherePluginConfig{ Enabled: true, Release: &vapi.HelmRelease{ @@ -32,7 +33,7 @@ func ConfigureVspherePlugin(vc *ValidatorConfig, config VsphereConfig) { Name: cfg.ValidatorPluginVsphere, Repository: fmt.Sprintf("%s/%s", cfg.ValidatorHelmRepository, cfg.ValidatorPluginVsphere), Version: cfg.ValidatorChartVersions[cfg.ValidatorPluginVsphere], - InsecureSkipTlsVerify: true, + InsecureSkipTLSVerify: true, }, }, ReleaseSecret: &Secret{ diff --git a/pkg/config/constants.go b/pkg/config/constants.go index 047e3aeb..0c5d412f 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -15,14 +15,15 @@ const ( ClusterConfigTemplate = "cluster-configuration.tmpl" KindImage = "kindest/node" - KindImageTag = "v1.27.11" + KindImageTag = "v1.30.2" NoProxyPrompt = "# Default NO_PROXY values are on the lines below.\n# Edit as you see fit (comments are ignored). The file should contain a list of NO_PROXY values, newline separated.\n# Type :wq to save and exit (if using vi).\n\n" // Validator constants ValidatorConfigFile = "validator.yaml" ValidatorKindClusterName = "validator-kind-cluster" ValidatorHelmRepository = "https://validator-labs.github.io" - ValidatorImageRegistry = "quay.io/validator-labs" + ValidatorImageRegistry = "quay.io" + ValidatorImageRepository = "validator-labs" ValidatorPluginAws = "validator-plugin-aws" ValidatorPluginAzure = "validator-plugin-azure" @@ -66,22 +67,29 @@ const ( var ( // Misc. - DefaultPodCIDR = "192.168.0.0/16" - DefaultServiceIPRange = "10.96.0.0/12" - HTTPSchemes = []string{"https://", "http://"} + DefaultPodCIDR = "192.168.0.0/16" + DefaultServiceIPRange = "10.96.0.0/12" + HTTPSchemes = []string{"https://", "http://"} + RegistryMirrors = []string{"docker.io", "gcr.io", "ghcr.io", "k8s.gcr.io", "registry.k8s.io", "quay.io", "*"} + RegistryMirrorSeparator = "::" // Command dirs ValidatorSubdirs = []string{"manifests"} // Validator + ValidatorImagePath = func() string { + return ValidatorImageRegistry + "/" + ValidatorImageRepository + } + PlacementTypeStatic = "Static" PlacementTypeDynamic = "Dynamic" PlacementTypes = []string{PlacementTypeStatic, PlacementTypeDynamic} + // TODO: centralize these in a single place referenced by validator & validatorctl ValidatorChartVersions = map[string]string{ - Validator: "v0.0.43", - ValidatorPluginAws: "v0.1.0", - ValidatorPluginAzure: "v0.0.11", + Validator: "v0.0.46", + ValidatorPluginAws: "v0.1.1", + ValidatorPluginAzure: "v0.0.12", ValidatorPluginNetwork: "v0.0.17", ValidatorPluginOci: "v0.0.10", ValidatorPluginVsphere: "v0.0.26", diff --git a/pkg/services/env_service.go b/pkg/services/env_service.go index 838e3042..dd9aa24d 100644 --- a/pkg/services/env_service.go +++ b/pkg/services/env_service.go @@ -2,27 +2,70 @@ package services import ( + "fmt" "time" "github.com/spectrocloud-labs/prompts-tui/prompts" cfg "github.com/validator-labs/validatorctl/pkg/config" log "github.com/validator-labs/validatorctl/pkg/logging" + "github.com/validator-labs/validatorctl/pkg/utils/network" ) -// Env represents the environment configuration +// Env represents the environment configuration. type Env struct { - HTTPProxy string `yaml:"httpProxy,omitempty"` - HTTPSProxy string `yaml:"httpsProxy,omitempty"` - NoProxy string `yaml:"noProxy,omitempty"` - PodCIDR *string `yaml:"podCIDR"` - ProxyCaCertData string `yaml:"proxyCaCertData,omitempty"` - ProxyCaCertName string `yaml:"proxyCaCertName,omitempty"` - ProxyCaCertPath string `yaml:"proxyCaCertPath,omitempty"` - ServiceIPRange *string `yaml:"serviceIPRange"` + HTTPProxy string `yaml:"httpProxy,omitempty"` + HTTPSProxy string `yaml:"httpsProxy,omitempty"` + NoProxy string `yaml:"noProxy,omitempty"` + PodCIDR *string `yaml:"podCIDR"` + ProxyCACert *CACert `yaml:"proxyCaCert,omitempty"` + ServiceIPRange *string `yaml:"serviceIPRange"` } -// ReadProxyProps prompts the user to configure proxy settings +// Hauler represents the hauler configuration for air-gapped installs. +type Hauler struct { + Host string `yaml:"host"` + Port int `yaml:"port"` + BasicAuth *BasicAuth `yaml:"basicAuth,omitempty"` + InsecureSkipTLSVerify bool `yaml:"insecureSkipTLSVerify"` + CACert *CACert `yaml:"caCert,omitempty"` + ReuseProxyCACert bool `yaml:"reuseProxyCACert,omitempty"` +} + +// Endpoint returns the base hauler registry URL. +func (h *Hauler) Endpoint() string { + return fmt.Sprintf("%s:%d", h.Host, h.Port) +} + +// KindImage returns the image with the local hauler registry endpoint. +func (h *Hauler) KindImage(image string) string { + return fmt.Sprintf("localhost:%d/%s", h.Port, image) +} + +// ChartEndpoint returns the hauler chart repository URL. +func (h *Hauler) ChartEndpoint() string { + return fmt.Sprintf("oci://%s/hauler", h.Endpoint()) +} + +// ImageEndpoint returns the hauler image repository URL. +func (h *Hauler) ImageEndpoint() string { + return fmt.Sprintf("%s/%s", h.Endpoint(), cfg.ValidatorImageRepository) +} + +// BasicAuth represents basic authentication credentials. +type BasicAuth struct { + Username string `yaml:"username"` + Password string `yaml:"password"` +} + +// CACert represents a CA certificate. +type CACert struct { + Data string `yaml:"data"` + Name string `yaml:"name"` + Path string `yaml:"path"` +} + +// ReadProxyProps prompts the user to configure proxy settings. func ReadProxyProps(e *Env) error { var err error @@ -48,13 +91,86 @@ func ReadProxyProps(e *Env) error { } // Proxy CA certificate - caCertPath, caCertName, caCertData, err := prompts.ReadCACert("Proxy CA certificate filepath", e.ProxyCaCertPath, "") + if e.ProxyCACert == nil { + e.ProxyCACert = &CACert{} + } + caCertPath, caCertName, caCertData, err := prompts.ReadCACert("Proxy CA certificate filepath", e.ProxyCACert.Path, "") if err != nil { return err } - e.ProxyCaCertData = string(caCertData) - e.ProxyCaCertName = caCertName - e.ProxyCaCertPath = caCertPath + e.ProxyCACert.Data = string(caCertData) + e.ProxyCACert.Name = caCertName + e.ProxyCACert.Path = caCertPath + } + + return nil +} + +// ReadHaulerProps prompts the user to configure hauler settings. +func ReadHaulerProps(h *Hauler, e *Env) error { + var err error + + // registry + if h.Host == "" { + h.Host = network.GetDefaultHostAddress() + } + h.Host, err = prompts.ReadText("Hauler Host (IPv4 address of primary NIC)", h.Host, false, -1) + if err != nil { + return err + } + if h.Port == 0 { + h.Port = 5000 + } + h.Port, err = prompts.ReadInt("Hauler Port", fmt.Sprintf("%d", h.Port), 1024, 65535) + if err != nil { + return err + } + + // basic auth + if h.BasicAuth == nil { + h.BasicAuth = &BasicAuth{} + } + h.BasicAuth.Username, h.BasicAuth.Password, err = prompts.ReadBasicCreds( + "Username", "Password", h.BasicAuth.Username, h.BasicAuth.Password, true, false, + ) + if err != nil { + return err + } + + // tls verification + h.InsecureSkipTLSVerify, err = prompts.ReadBool("Allow Insecure Connection (Bypass x509 Verification)", true) + if err != nil { + return err + } + if h.InsecureSkipTLSVerify { + return nil + } + + // ca cert + if e.ProxyCACert.Path != "" { + h.ReuseProxyCACert, err = prompts.ReadBool("Reuse proxy CA cert for Hauler registry", true) + if err != nil { + return err + } + } + if h.CACert == nil { + h.CACert = &CACert{} + } + if h.ReuseProxyCACert { + h.CACert = e.ProxyCACert + return nil + } + caCertPath, caCertName, caCertData, err := prompts.ReadCACert("Hauler CA certificate filepath", h.CACert.Path, "") + if err != nil { + return err + } + + if caCertPath == "" { + h = nil + } else { + h.CACert.Data = string(caCertData) + h.CACert.Name = caCertName + h.CACert.Path = caCertPath } return nil diff --git a/pkg/services/validator/aws.go b/pkg/services/validator/aws.go index 88422c6b..cf14864a 100644 --- a/pkg/services/validator/aws.go +++ b/pkg/services/validator/aws.go @@ -35,6 +35,9 @@ func readAwsPlugin(vc *components.ValidatorConfig, k8sClient kubernetes.Interfac if err := readHelmRelease(cfg.ValidatorPluginAws, k8sClient, vc, c.Release, c.ReleaseSecret); err != nil { return err } + + log.Header("AWS Configuration") + if err := readAwsCredentials(c, k8sClient); err != nil { return errors.Wrap(err, "failed to read AWS credentials") } diff --git a/pkg/services/validator/aws_test.go b/pkg/services/validator/aws_test.go index 5fbcc5e4..78076b6a 100644 --- a/pkg/services/validator/aws_test.go +++ b/pkg/services/validator/aws_test.go @@ -16,6 +16,9 @@ import ( ) var awsDummyConfig = &components.ValidatorConfig{ + AirgapConfig: &components.AirgapConfig{ + Enabled: false, + }, AWSPlugin: &components.AWSPluginConfig{ Release: &v1alpha1.HelmRelease{ Chart: v1alpha1.HelmChart{}, diff --git a/pkg/services/validator/azure.go b/pkg/services/validator/azure.go index 325ec73d..b9047841 100644 --- a/pkg/services/validator/azure.go +++ b/pkg/services/validator/azure.go @@ -49,6 +49,9 @@ func readAzurePlugin(vc *components.ValidatorConfig, k8sClient kubernetes.Interf if err := readHelmRelease(cfg.ValidatorPluginAzure, k8sClient, vc, c.Release, c.ReleaseSecret); err != nil { return fmt.Errorf("failed to read Helm release: %w", err) } + + log.Header("Azure Configuration") + if err := readAzureCredentials(c, k8sClient); err != nil { return errors.Wrap(err, "failed to read Azure credentials") } diff --git a/pkg/services/validator/common.go b/pkg/services/validator/common.go index 2a4e59e9..c528a97d 100644 --- a/pkg/services/validator/common.go +++ b/pkg/services/validator/common.go @@ -25,6 +25,7 @@ import ( var errNoRulesEnabled = errors.New("no validation rules enabled") func readHelmRelease(name string, k8sClient kubernetes.Interface, vc *components.ValidatorConfig, r *vapi.HelmRelease, rs *components.Secret) error { + log.Header(fmt.Sprintf("%s Helm Chart Configuration", name)) var err error defaultRepo := fmt.Sprintf("%s/%s", cfg.ValidatorHelmRepository, name) @@ -37,15 +38,21 @@ func readHelmRelease(name string, k8sClient kubernetes.Interface, vc *components r.Chart.Name = name rs.Name = fmt.Sprintf("validator-helm-release-%s", name) - r.Chart.Repository, err = prompts.ReadText(fmt.Sprintf("%s Helm repository", name), defaultRepo, false, -1) - if err != nil { - return err + if vc.AirgapConfig.Enabled { + r.Chart.Repository = vc.AirgapConfig.Hauler.ChartEndpoint() + log.InfoCLI("Using local Hauler repository: %s", vc.AirgapConfig.Hauler.ChartEndpoint()) + } else { + r.Chart.Repository, err = prompts.ReadText(fmt.Sprintf("%s Helm repository", name), defaultRepo, false, -1) + if err != nil { + return err + } } - versionPrompt := fmt.Sprintf("%s version", name) if vc.UseFixedVersions { r.Chart.Version = cfg.ValidatorChartVersions[name] + log.InfoCLI("Using fixed version: %s for %s chart", r.Chart.Version, r.Chart.Name) } else { + versionPrompt := fmt.Sprintf("%s version", name) availableVersions, err := getReleasesFromHelmRepo(r.Chart.Repository) // Ignore error and fall back to reading version from the command line. // Errors may occur in air-gapped environments or misconfigured helm repos. @@ -86,8 +93,8 @@ func readHelmCredentials(r *vapi.HelmRelease, rs *components.Secret, k8sClient k rsCp := deepcopy.Copy(vc.ReleaseSecret).(*components.Secret) *rs = *rsCp r.Chart.AuthSecretName = vc.Release.Chart.AuthSecretName - r.Chart.CaFile = vc.Release.Chart.CaFile - r.Chart.InsecureSkipTlsVerify = vc.Release.Chart.InsecureSkipTlsVerify + r.Chart.CAFile = vc.Release.Chart.CAFile + r.Chart.InsecureSkipTLSVerify = vc.Release.Chart.InsecureSkipTLSVerify return nil } @@ -100,9 +107,9 @@ func readHelmCredentials(r *vapi.HelmRelease, rs *components.Secret, k8sClient k if err != nil { return err } - r.Chart.CaFile = rs.CaCertFile + r.Chart.CAFile = rs.CaCertFile } - r.Chart.InsecureSkipTlsVerify = insecure + r.Chart.InsecureSkipTLSVerify = insecure useBasicAuth, err := prompts.ReadBool("Configure Helm basic authentication", false) if err != nil { diff --git a/pkg/services/validator/network.go b/pkg/services/validator/network.go index 44e6a6a0..188fceeb 100644 --- a/pkg/services/validator/network.go +++ b/pkg/services/validator/network.go @@ -24,6 +24,7 @@ func readNetworkPlugin(vc *components.ValidatorConfig, k8sClient kubernetes.Inte return err } + log.Header("Network Configuration") ruleNames := make([]string, 0) if err := configureDNSRules(c, &ruleNames); err != nil { diff --git a/pkg/services/validator/network_test.go b/pkg/services/validator/network_test.go index 5f169796..f325c52e 100644 --- a/pkg/services/validator/network_test.go +++ b/pkg/services/validator/network_test.go @@ -16,6 +16,9 @@ import ( ) var networkDummyConfig = &components.ValidatorConfig{ + AirgapConfig: &components.AirgapConfig{ + Enabled: false, + }, NetworkPlugin: &components.NetworkPluginConfig{ Release: &v1alpha1.HelmRelease{ Chart: v1alpha1.HelmChart{}, diff --git a/pkg/services/validator/oci.go b/pkg/services/validator/oci.go index 89c49698..28d72757 100644 --- a/pkg/services/validator/oci.go +++ b/pkg/services/validator/oci.go @@ -24,6 +24,9 @@ func readOciPlugin(vc *components.ValidatorConfig, k8sClient kubernetes.Interfac if err := readHelmRelease(cfg.ValidatorPluginOci, k8sClient, vc, c.Release, c.ReleaseSecret); err != nil { return err } + + log.Header("OCI Configuration") + authSecretNames, err := configureAuthSecrets(c, k8sClient) if err != nil { return err diff --git a/pkg/services/validator/validator_service.go b/pkg/services/validator/validator_service.go index e60b8648..faaa713d 100644 --- a/pkg/services/validator/validator_service.go +++ b/pkg/services/validator/validator_service.go @@ -31,7 +31,7 @@ var ( } plugins = make([]string, 0, len(pluginFuncs)) - imageRegistry = cfg.ValidatorImageRegistry + imageRegistry = cfg.ValidatorImagePath() ) func init() { @@ -49,6 +49,7 @@ func ReadValidatorConfig(c *cfg.Config, tc *cfg.TaskConfig, vc *components.Valid var err error var k8sClient kubernetes.Interface + log.Header("Kind Configuration") vc.KindConfig.UseKindCluster, err = prompts.ReadBool("Provision & use kind cluster", true) if err != nil { return err @@ -65,25 +66,37 @@ func ReadValidatorConfig(c *cfg.Config, tc *cfg.TaskConfig, vc *components.Valid } } - if vc.ImageRegistry != "" { - imageRegistry = vc.ImageRegistry - } - vc.ImageRegistry, err = prompts.ReadText("Validator image registry", imageRegistry, false, -1) - if err != nil { + log.Header("Air-gapped Configuration") + if err := readAirgapConfig(vc); err != nil { return err } + if vc.AirgapConfig.Enabled { + vc.ImageRegistry = vc.AirgapConfig.Hauler.ImageEndpoint() + } else { + if vc.ImageRegistry != "" { + imageRegistry = vc.ImageRegistry + } + vc.ImageRegistry, err = prompts.ReadText("Validator image registry", imageRegistry, false, -1) + if err != nil { + return err + } + } + log.Header("Proxy Configuration") if err := readProxyConfig(vc); err != nil { return err } + + log.Header("Sink Configuration") if err := readSinkConfig(vc, k8sClient); err != nil { return err } + if err := readHelmRelease(cfg.Validator, k8sClient, vc, vc.Release, vc.ReleaseSecret); err != nil { return err } - log.Header("Enter Validator Plugin Configuration") + log.Header("Validator Plugin Configuration") vc.AWSPlugin.Enabled, err = prompts.ReadBool("Enable AWS plugin", true) if err != nil { @@ -135,6 +148,7 @@ func ReadValidatorConfig(c *cfg.Config, tc *cfg.TaskConfig, vc *components.Valid } } + log.Header("Finalize Configuration") restart, err := prompts.ReadBool("Restart configuration", false) if err != nil { return err @@ -176,13 +190,17 @@ func UpdateValidatorCredentials(c *components.ValidatorConfig) error { } } - log.InfoCLI("Configure Helm release credentials for validator chart") + if c.AirgapConfig.Enabled { + if err := readAirgapConfig(c); err != nil { + return err + } + } + if err := readHelmCredentials(c.Release, c.ReleaseSecret, k8sClient, c); err != nil { return err } if c.AWSPlugin != nil && c.AWSPlugin.Enabled { - log.InfoCLI("Configure Helm release credentials for validator-plugin-aws chart") if err := readHelmCredentials(c.AWSPlugin.Release, c.AWSPlugin.ReleaseSecret, k8sClient, c); err != nil { return err } @@ -191,7 +209,6 @@ func UpdateValidatorCredentials(c *components.ValidatorConfig) error { } } if c.AzurePlugin != nil && c.AzurePlugin.Enabled { - log.InfoCLI("Configure Helm release credentials for validator-plugin-azure chart") if err := readHelmCredentials(c.AzurePlugin.Release, c.AzurePlugin.ReleaseSecret, k8sClient, c); err != nil { return err } @@ -200,7 +217,6 @@ func UpdateValidatorCredentials(c *components.ValidatorConfig) error { } } if c.OCIPlugin != nil && c.OCIPlugin.Enabled { - log.InfoCLI("Configure Helm release credentials for validator-plugin-oci chart") if err := readHelmCredentials(c.OCIPlugin.Release, c.OCIPlugin.ReleaseSecret, k8sClient, c); err != nil { return err } @@ -211,7 +227,6 @@ func UpdateValidatorCredentials(c *components.ValidatorConfig) error { } } if c.VspherePlugin != nil && c.VspherePlugin.Enabled { - log.InfoCLI("Configure Helm release credentials for validator-plugin-vsphere chart") if err = readHelmCredentials(c.VspherePlugin.Release, c.VspherePlugin.ReleaseSecret, k8sClient, c); err != nil { return err } @@ -223,6 +238,15 @@ func UpdateValidatorCredentials(c *components.ValidatorConfig) error { return nil } +func readAirgapConfig(vc *components.ValidatorConfig) (err error) { + vc.AirgapConfig.Enabled, err = prompts.ReadBool("Configure Hauler for air-gapped installation", false) + if err != nil || !vc.AirgapConfig.Enabled { + return + } + vc.UseFixedVersions = true + return services.ReadHaulerProps(vc.AirgapConfig.Hauler, vc.ProxyConfig.Env) +} + func readProxyConfig(vc *components.ValidatorConfig) error { vc.ProxyConfig.Env.PodCIDR = &cfg.DefaultPodCIDR vc.ProxyConfig.Env.ServiceIPRange = &cfg.DefaultServiceIPRange @@ -238,7 +262,7 @@ func readProxyConfig(vc *components.ValidatorConfig) error { if err := services.ReadProxyProps(vc.ProxyConfig.Env); err != nil { return err } - vc.ProxyConfig.Enabled = vc.ProxyConfig.Env.ProxyCaCertPath != "" + vc.ProxyConfig.Enabled = vc.ProxyConfig.Env.ProxyCACert.Path != "" return nil } diff --git a/pkg/services/validator/vmware.go b/pkg/services/validator/vmware.go index b59c6dd0..58bf282d 100644 --- a/pkg/services/validator/vmware.go +++ b/pkg/services/validator/vmware.go @@ -52,6 +52,9 @@ func readVspherePlugin(vc *components.ValidatorConfig, k8sClient kubernetes.Inte if err := readHelmRelease(cfg.ValidatorPluginVsphere, k8sClient, vc, c.Release, c.ReleaseSecret); err != nil { return err } + + log.Header("vSphere Configuration") + if err := readVsphereCredentials(c, k8sClient); err != nil { return errors.Wrap(err, "failed to read vSphere credentials") } @@ -252,6 +255,9 @@ func selectEsxiHosts(ctx context.Context, datacenter string, clusterName string, return nil, err } selectedHosts = append(selectedHosts, hostName) + hostList = slices.DeleteFunc(hostList, func(s string) bool { + return s == hostName + }) add, err := prompts.ReadBool("Add another ESXi Host", false) if err != nil { @@ -320,8 +326,20 @@ func configureRolePrivilegeRules(c *components.VspherePluginConfig, ruleNames *[ } func readRolePrivilegeRule(c *components.VspherePluginConfig, r *components.VsphereRolePrivilegeRule, idx int, ruleNames *[]string, isAdmin bool) error { - err := initVsphereRule(r, "role privilege", "The rule's vSphere privilege set will be replaced.", ruleNames) - if err != nil { + var err error + var initMsg string + reconfigurePrivileges := true + + if r.Name != "" { + reconfigurePrivileges, err = prompts.ReadBool("Reconfigure privilege set for role privilege rule", false) + if err != nil { + return err + } + if reconfigurePrivileges { + initMsg = "The rule's vSphere privilege set will be replaced." + } + } + if err := initVsphereRule(r, "role privilege", initMsg, ruleNames); err != nil { return err } @@ -334,15 +352,19 @@ func readRolePrivilegeRule(c *components.VspherePluginConfig, r *components.Vsph log.InfoCLI(`Privilege validation rule will be applied for username %s`, c.Account.Username) r.Username = c.Account.Username } - privileges, err := LoadPrivileges(cfg.ValidatorVspherePrivilegeFile) - if err != nil { - return err - } - privileges, err = selectPrivileges(privileges) - if err != nil { - return err + + if reconfigurePrivileges { + privileges, err := LoadPrivileges(cfg.ValidatorVspherePrivilegeFile) + if err != nil { + return err + } + privileges, err = selectPrivileges(privileges) + if err != nil { + return err + } + r.Privileges = privileges } - r.Privileges = privileges + if idx == -1 { c.VsphereRolePrivilegeRules = append(c.VsphereRolePrivilegeRules, *r) c.Validator.RolePrivilegeValidationRules = append(c.Validator.RolePrivilegeValidationRules, r.GenericRolePrivilegeValidationRule) @@ -350,6 +372,7 @@ func readRolePrivilegeRule(c *components.VspherePluginConfig, r *components.Vsph c.VsphereRolePrivilegeRules[idx] = *r c.Validator.RolePrivilegeValidationRules[idx] = r.GenericRolePrivilegeValidationRule } + return nil } @@ -446,12 +469,24 @@ func configureEntityPrivilegeRules(ctx context.Context, c *components.VspherePlu } func readEntityPrivilegeRule(ctx context.Context, c *components.VspherePluginConfig, r *components.VsphereEntityPrivilegeRule, driver vsphere.VsphereDriver, idx int, ruleNames *[]string, isAdmin bool) error { - err := initVsphereRule(r, "entity privilege", "The rule's vSphere privilege set will be replaced.", ruleNames) - if err != nil { + var err error + var initMsg string + reconfigureEntity := true + + if r.Name != "" { + reconfigureEntity, err = prompts.ReadBool("Reconfigure entity and privilege set for entity privilege rule", false) + if err != nil { + return err + } + if reconfigureEntity { + initMsg = "The rule's entity and privilege set will be replaced." + } + } + if err := initVsphereRule(r, "entity privilege", initMsg, ruleNames); err != nil { return err } - if err := readCustomEntityPrivileges(ctx, c, r, driver, isAdmin); err != nil { + if err := readEntityPrivileges(ctx, c, r, driver, isAdmin, reconfigureEntity); err != nil { return err } @@ -466,33 +501,34 @@ func readEntityPrivilegeRule(ctx context.Context, c *components.VspherePluginCon return nil } -func readCustomEntityPrivileges(ctx context.Context, c *components.VspherePluginConfig, r *components.VsphereEntityPrivilegeRule, driver vsphere.VsphereDriver, isAdmin bool) error { +func readEntityPrivileges(ctx context.Context, c *components.VspherePluginConfig, r *components.VsphereEntityPrivilegeRule, driver vsphere.VsphereDriver, isAdmin, reconfigureEntity bool) error { var err error - if r.Username == "" { - if isAdmin { - r.Username, err = prompts.ReadTextRegex("vSphere username to validate entity privileges for", r.Username, "Invalid vSphere username", cfg.VSphereUsernameRegex) - if err != nil { - return err - } - } else { - log.InfoCLI(`Privilege validation rule will be applied for username %s`, c.Account.Username) - r.Username = c.Account.Username + if isAdmin { + r.Username, err = prompts.ReadTextRegex("vSphere username to validate entity privileges for", r.Username, "Invalid vSphere username", cfg.VSphereUsernameRegex) + if err != nil { + return err } + } else { + log.InfoCLI(`Privilege validation rule will be applied for username %s`, c.Account.Username) + r.Username = c.Account.Username + } + if reconfigureEntity { r.EntityType, r.EntityName, r.ClusterName, err = getEntityInfo(ctx, "", "Entity Type", c.Validator.Datacenter, cfg.ValidatorPluginVsphereEntities, driver) if err != nil { return err } + privileges, err := LoadPrivileges(cfg.ValidatorVspherePrivilegeFile) + if err != nil { + return err + } + r.Privileges, err = selectPrivileges(privileges) + if err != nil { + return err + } } - privileges, err := LoadPrivileges(cfg.ValidatorVspherePrivilegeFile) - if err != nil { - return err - } - r.Privileges, err = selectPrivileges(privileges) - if err != nil { - return err - } + return nil } diff --git a/pkg/services/validator/vmware_test.go b/pkg/services/validator/vmware_test.go index b324839e..0a087b6b 100644 --- a/pkg/services/validator/vmware_test.go +++ b/pkg/services/validator/vmware_test.go @@ -19,6 +19,9 @@ import ( ) var vSphereDummyConfig = &components.ValidatorConfig{ + AirgapConfig: &components.AirgapConfig{ + Enabled: false, + }, VspherePlugin: &components.VspherePluginConfig{ Release: &v1alpha1.HelmRelease{ Chart: v1alpha1.HelmChart{}, diff --git a/pkg/utils/embed/resources/kind/cluster-configuration.tmpl b/pkg/utils/embed/resources/kind/cluster-configuration.tmpl index 82ee2667..0ee8997b 100644 --- a/pkg/utils/embed/resources/kind/cluster-configuration.tmpl +++ b/pkg/utils/embed/resources/kind/cluster-configuration.tmpl @@ -8,18 +8,18 @@ networking: nodes: - role: control-plane image: {{ .Image }} -{{- if or .Env.ProxyCaCertPath (and .RegistryEndpoint (eq .RegistryInsecure "false")) }} +{{- $insecure := .RegistryInsecure }} +{{- if or .Env.ProxyCACert.Path (and .RegistryEndpoint (eq $insecure "false")) }} extraMounts: {{- end }} -{{- if .Env.ProxyCaCertPath }} - - hostPath: {{ .Env.ProxyCaCertPath }} - containerPath: {{ printf "%s/%s" $cert_location .Env.ProxyCaCertName }} +{{- if .Env.ProxyCACert.Path }} + - hostPath: {{ .Env.ProxyCACert.Path }} + containerPath: {{ printf "%s/%s" $cert_location .Env.ProxyCACert.Name }} {{- end }} {{- if .RegistryEndpoint }} -{{- $mirrorEndpoint := .RegistryMirrorEndpoint }} -{{- if and (eq .RegistryInsecure "false") (not .ReusedProxyCACert) }} - - hostPath: /etc/docker/certs.d/{{ .RegistryEndpoint }}/{{ .RegistryCaCertName }} - containerPath: {{ printf "%s/%s" $cert_location .RegistryCaCertName }} +{{- if and (eq $insecure "false") (not .ReusedProxyCACert) }} + - hostPath: /etc/docker/certs.d/{{ .RegistryEndpoint }}/{{ .RegistryCACertName }} + containerPath: {{ printf "%s/%s" $cert_location .RegistryCACertName }} {{- end }} containerdConfigPatches: - |- @@ -29,14 +29,18 @@ containerdConfigPatches: username = "{{ .RegistryUsername }}" {{- end }} [plugins."io.containerd.grpc.v1.cri".registry.configs."{{ .RegistryEndpoint }}".tls] - {{- if eq .RegistryInsecure "true" }} - insecure_skip_verify = {{ .RegistryInsecure }} + {{- if eq $insecure "true" }} + insecure_skip_verify = {{ $insecure }} {{- else }} - ca_file = "{{ printf "%s/%s" $cert_location .RegistryCaCertName }}" + ca_file = "{{ printf "%s/%s" $cert_location .RegistryCACertName }}" {{- end }} {{- range .RegistryMirrors }} {{- $registryMirror := split "::" . }} [plugins."io.containerd.grpc.v1.cri".registry.mirrors."{{ $registryMirror._0 }}"] + {{- if eq $insecure "true" }} + endpoint = ["http://{{ $registryMirror._1 }}"] + {{- else }} endpoint = ["{{ $registryMirror._1 }}"] + {{- end }} {{- end }} {{- end }} \ No newline at end of file diff --git a/pkg/utils/embed/resources/validator/validator-base-values.tmpl b/pkg/utils/embed/resources/validator/validator-base-values.tmpl index 30133997..cb75a197 100644 --- a/pkg/utils/embed/resources/validator/validator-base-values.tmpl +++ b/pkg/utils/embed/resources/validator/validator-base-values.tmpl @@ -12,7 +12,7 @@ controllerManager: - ALL image: repository: gcr.io/kubebuilder/kube-rbac-proxy - tag: v0.14.1 + tag: v0.16.0 resources: limits: cpu: 500m diff --git a/pkg/utils/embed/resources/validator/validator-plugin-aws-values.tmpl b/pkg/utils/embed/resources/validator/validator-plugin-aws-values.tmpl index 97c13636..23610379 100644 --- a/pkg/utils/embed/resources/validator/validator-plugin-aws-values.tmpl +++ b/pkg/utils/embed/resources/validator/validator-plugin-aws-values.tmpl @@ -12,7 +12,7 @@ controllerManager: - ALL image: repository: gcr.io/kubebuilder/kube-rbac-proxy - tag: v0.14.1 + tag: v0.16.0 resources: limits: cpu: 500m diff --git a/pkg/utils/embed/resources/validator/validator-plugin-network-values.tmpl b/pkg/utils/embed/resources/validator/validator-plugin-network-values.tmpl index 8fc8da8f..8cab375b 100644 --- a/pkg/utils/embed/resources/validator/validator-plugin-network-values.tmpl +++ b/pkg/utils/embed/resources/validator/validator-plugin-network-values.tmpl @@ -12,7 +12,7 @@ controllerManager: - ALL image: repository: gcr.io/kubebuilder/kube-rbac-proxy - tag: v0.14.1 + tag: v0.16.0 resources: limits: cpu: 500m diff --git a/pkg/utils/embed/resources/validator/validator-plugin-vsphere-values.tmpl b/pkg/utils/embed/resources/validator/validator-plugin-vsphere-values.tmpl index 3bb2d96f..2d6f5044 100644 --- a/pkg/utils/embed/resources/validator/validator-plugin-vsphere-values.tmpl +++ b/pkg/utils/embed/resources/validator/validator-plugin-vsphere-values.tmpl @@ -12,7 +12,7 @@ controllerManager: - ALL image: repository: gcr.io/kubebuilder/kube-rbac-proxy - tag: v0.14.1 + tag: v0.16.0 resources: limits: cpu: 500m diff --git a/pkg/utils/kind/kind.go b/pkg/utils/kind/kind.go index 7d643f92..ceee6f24 100644 --- a/pkg/utils/kind/kind.go +++ b/pkg/utils/kind/kind.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "regexp" + "strconv" "strings" "github.com/pkg/errors" @@ -80,19 +81,8 @@ func DeleteCluster(name string) error { return nil } -// DefaultKindArgs returns the default arguments for a Kind cluster configuration -func DefaultKindArgs() map[string]interface{} { - return map[string]interface{}{ - "Env": env.Env{ - PodCIDR: &cfg.DefaultPodCIDR, - ServiceIPRange: &cfg.DefaultServiceIPRange, - }, - "Image": fmt.Sprintf("%s:%s", cfg.KindImage, cfg.KindImageTag), - } -} - -// AdvancedConfig renders a kind cluster configuration file with optional proxy and registry mirror customizations -func AdvancedConfig(env *env.Env, kindConfig string) error { +// RenderKindConfig renders a kind cluster configuration file with optional proxy and registry mirror customizations +func RenderKindConfig(env *env.Env, hauler *env.Hauler, kindConfig string) error { image := fmt.Sprintf("%s:%s", cfg.KindImage, cfg.KindImageTag) clusterConfigArgs := map[string]interface{}{ @@ -100,9 +90,43 @@ func AdvancedConfig(env *env.Env, kindConfig string) error { "Image": image, } + // air-gapped configuration + if hauler != nil { + ep := hauler.Endpoint() + clusterConfigArgs["Image"] = hauler.KindImage(image) + clusterConfigArgs["RegistryEndpoint"] = ep + clusterConfigArgs["RegistryInsecure"] = strconv.FormatBool(hauler.InsecureSkipTLSVerify) + clusterConfigArgs["RegistryMirrors"] = defaultMirrorRegistries(ep) + clusterConfigArgs["ReusedProxyCACert"] = hauler.ReuseProxyCACert + + if hauler.CACert != nil { + clusterConfigArgs["RegistryCACertName"] = hauler.CACert.Name + } + if hauler.BasicAuth != nil { + clusterConfigArgs["RegistryUsername"] = hauler.BasicAuth.Username + clusterConfigArgs["RegistryPassword"] = hauler.BasicAuth.Password + } + } + return embed_utils.RenderTemplate(clusterConfigArgs, cfg.Kind, cfg.ClusterConfigTemplate, kindConfig) } +// defaultMirrorRegistries returns a comma-separated string of default registry mirrors +func defaultMirrorRegistries(registryEndpoint string) []string { + if registryEndpoint == "" { + return nil + } + mirrorRegistries := make([]string, 0) + for _, registry := range cfg.RegistryMirrors { + // Add OCI format suffix (/v2) + registryMirrorEndpoint := fmt.Sprintf("%s/v2", registryEndpoint) + mirrorRegistries = append(mirrorRegistries, + fmt.Sprintf("%s%s%s", registry, cfg.RegistryMirrorSeparator, registryMirrorEndpoint), + ) + } + return mirrorRegistries +} + func getClusters() ([]string, error) { cmd := exec.Command(exec_utils.Kind, "get", "clusters") //#nosec G204 diff --git a/pkg/utils/kind/kind_test.go b/pkg/utils/kind/kind_test.go index e6951cc6..34780319 100644 --- a/pkg/utils/kind/kind_test.go +++ b/pkg/utils/kind/kind_test.go @@ -11,38 +11,42 @@ import ( ) func TestRenderKindConfig(t *testing.T) { - subtests := []struct { + tests := []struct { name string env *env.Env + hauler *env.Hauler expected string }{ { name: "Kind config w/ proxy CA cert", env: &env.Env{ - PodCIDR: &cfg.DefaultPodCIDR, - ServiceIPRange: &cfg.DefaultServiceIPRange, - ProxyCaCertName: "hosts", - ProxyCaCertPath: "/etc/hosts", + PodCIDR: &cfg.DefaultPodCIDR, + ServiceIPRange: &cfg.DefaultServiceIPRange, + ProxyCACert: &env.CACert{ + Name: "hosts", + Path: "/etc/hosts", + }, }, expected: "kindconfig-shared-ca.yaml", }, { name: "Kind config basic", env: &env.Env{ + ProxyCACert: &env.CACert{}, PodCIDR: &cfg.DefaultPodCIDR, ServiceIPRange: &cfg.DefaultServiceIPRange, }, expected: "kindconfig-basic.yaml", }, } - for _, subtest := range subtests { + for _, tt := range tests { kindConfig := file.UnitTestFile("kindconfig.tmp") - if err := AdvancedConfig(subtest.env, kindConfig); err != nil { + if err := RenderKindConfig(tt.env, tt.hauler, kindConfig); err != nil { t.Fatalf("Command Execution Failed. %v", err) } - expectedBytes, err := os.ReadFile(file.UnitTestFile(subtest.expected)) + expectedBytes, err := os.ReadFile(file.UnitTestFile(tt.expected)) if err != nil { - t.Fatalf("failed to read expected file: %s: %v", subtest.expected, err) + t.Fatalf("failed to read expected file: %s: %v", tt.expected, err) } renderedBytes, err := os.ReadFile(kindConfig) if err != nil { diff --git a/pkg/utils/network/network.go b/pkg/utils/network/network.go new file mode 100644 index 00000000..9bf843a2 --- /dev/null +++ b/pkg/utils/network/network.go @@ -0,0 +1,59 @@ +// Package network provides network utility functions. +package network + +import ( + "errors" + "net" + "os/exec" + "strings" + + log "github.com/validator-labs/validatorctl/pkg/logging" +) + +// GetDefaultHostAddress returns the default host IPv4 address. +func GetDefaultHostAddress() string { + devName, err := DiscoverDefaultGatewayDevice() + if err != nil { + log.Error("failed to discover default gateway device name: %v", err) + return "" + } + return GetInterfaceIPV4Address(devName) +} + +// DiscoverDefaultGatewayDevice discovers the interface name of the default gateway device. +func DiscoverDefaultGatewayDevice() (string, error) { + cmd := exec.Command("ip", "route", "show", "default") + output, err := cmd.Output() + if err != nil { + log.Error("failed to execute command '%s': %v", cmd.String(), err) + return "", err + } + fields := strings.Fields(string(output)) + for i, field := range fields { + if field == "dev" && i+1 < len(fields) { + deviceName := fields[i+1] + return deviceName, nil + } + } + return "", errors.New("no 'dev' in 'ip route show default' output") +} + +// GetInterfaceIPV4Address returns the IPv4 address of the given interface. +func GetInterfaceIPV4Address(ifName string) string { + nic, err := net.InterfaceByName(ifName) + if err != nil { + return "" + } + addresses, err := nic.Addrs() + if err != nil { + return "" + } + for _, addr := range addresses { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet.IP.To4() != nil { + return ipnet.IP.String() + } + } + } + return "" +} diff --git a/tests/integration/_validator/testcases/data/validator.yaml b/tests/integration/_validator/testcases/data/validator.yaml index e4cc7ce4..9af1f4a0 100644 --- a/tests/integration/_validator/testcases/data/validator.yaml +++ b/tests/integration/_validator/testcases/data/validator.yaml @@ -13,6 +13,8 @@ helmReleaseSecret: exists: false imageRegistry: quay.io/validator-labs useFixedVersion: false +airgapConfig: + enabled: false kindConfig: useKindCluster: true kindClusterName: "" @@ -30,6 +32,10 @@ sinkConfig: proxyConfig: enabled: false env: + proxyCaCert: + data: "" + name: "" + path: "" podCIDR: 172.16.0.0/20 serviceIPRange: 10.155.0.0/24 awsPlugin: diff --git a/tests/integration/_validator/testcases/test_validator.go b/tests/integration/_validator/testcases/test_validator.go index 81e58612..55f51ee2 100644 --- a/tests/integration/_validator/testcases/test_validator.go +++ b/tests/integration/_validator/testcases/test_validator.go @@ -100,6 +100,9 @@ func (t *ValidatorTest) testDeployInteractive(ctx *test.TestContext) (tr *test.T // Kind "y", // provision & use kind cluster + // Air-gapped + "n", // enable air-gapped mode + // Image registry "quay.io/validator-labs", // validator image registry diff --git a/tests/unit-test-data/kindconfig-basic.yaml b/tests/unit-test-data/kindconfig-basic.yaml index a11c8313..39d8fc0c 100644 --- a/tests/unit-test-data/kindconfig-basic.yaml +++ b/tests/unit-test-data/kindconfig-basic.yaml @@ -6,4 +6,4 @@ networking: disableDefaultCNI: false nodes: - role: control-plane - image: kindest/node:v1.27.11 \ No newline at end of file + image: kindest/node:v1.30.2 \ No newline at end of file diff --git a/tests/unit-test-data/kindconfig-shared-ca.yaml b/tests/unit-test-data/kindconfig-shared-ca.yaml index 41cc62d1..62f54427 100644 --- a/tests/unit-test-data/kindconfig-shared-ca.yaml +++ b/tests/unit-test-data/kindconfig-shared-ca.yaml @@ -6,7 +6,7 @@ networking: disableDefaultCNI: false nodes: - role: control-plane - image: kindest/node:v1.27.11 + image: kindest/node:v1.30.2 extraMounts: - hostPath: /etc/hosts containerPath: /usr/local/share/ca-certificates/hosts \ No newline at end of file