mirror of
https://github.com/clastix/kamaji.git
synced 2026-02-28 16:50:29 +00:00
Compare commits
32 Commits
edge-24.10
...
edge-24.12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9171f46c60 | ||
|
|
6244f8c524 | ||
|
|
99784dfa47 | ||
|
|
b6e1b49ba4 | ||
|
|
378dfb9b9d | ||
|
|
2b17282b0e | ||
|
|
1c8c67b95b | ||
|
|
11e1e6c25b | ||
|
|
7904b4d04a | ||
|
|
aaad06870e | ||
|
|
305dc82de1 | ||
|
|
1a1f7c42d7 | ||
|
|
2fda2b0148 | ||
|
|
59fa575d20 | ||
|
|
b334ea59f1 | ||
|
|
792b118f79 | ||
|
|
e330690b7f | ||
|
|
c4a5b4a5fd | ||
|
|
303bc07c31 | ||
|
|
6b6370885a | ||
|
|
495890e165 | ||
|
|
0c0111094e | ||
|
|
fdd0035915 | ||
|
|
7c0eb8d41d | ||
|
|
1bfbca5e19 | ||
|
|
2b54d83a51 | ||
|
|
12248dea3d | ||
|
|
4e8c2b66c0 | ||
|
|
3b1020a8f3 | ||
|
|
986f2ed114 | ||
|
|
674923c036 | ||
|
|
f3c6a7a41e |
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -8,9 +8,12 @@ updates:
|
||||
commit-message:
|
||||
prefix: "feat(deps)"
|
||||
groups:
|
||||
arrow:
|
||||
k8s:
|
||||
patterns:
|
||||
- "k8s.io*"
|
||||
etcd:
|
||||
patterns:
|
||||
- "go.etcd.io/etcd/*"
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
|
||||
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6.1.1
|
||||
with:
|
||||
version: v1.54.2
|
||||
version: v1.62.2
|
||||
only-new-issues: false
|
||||
args: --timeout 5m --config .golangci.yml
|
||||
diff:
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
linters-settings:
|
||||
revive:
|
||||
rules:
|
||||
- name: dot-imports
|
||||
arguments:
|
||||
- allowedPackages:
|
||||
- "github.com/onsi/ginkgo/v2"
|
||||
- "github.com/onsi/gomega"
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
@@ -13,16 +20,14 @@ linters:
|
||||
disable:
|
||||
- depguard
|
||||
- wrapcheck
|
||||
- gomnd
|
||||
- scopelint
|
||||
- mnd
|
||||
- varnamelen
|
||||
- testpackage
|
||||
- tagliatelle
|
||||
- paralleltest
|
||||
- ireturn
|
||||
- goerr113
|
||||
- err113
|
||||
- gochecknoglobals
|
||||
- exhaustivestruct
|
||||
- wsl
|
||||
- exhaustive
|
||||
- nosprintfhostport
|
||||
@@ -39,13 +44,7 @@ linters:
|
||||
- cyclop
|
||||
- gocognit
|
||||
- nestif
|
||||
- perfsprint
|
||||
# deprecated linters
|
||||
- deadcode
|
||||
- golint
|
||||
- interfacer
|
||||
- structcheck
|
||||
- varcheck
|
||||
- nosnakecase
|
||||
- ifshort
|
||||
- maligned
|
||||
- exportloopref
|
||||
enable-all: true
|
||||
|
||||
@@ -12,6 +12,7 @@ Feel free to open a Pull-Request to get yours listed.
|
||||
| End-user | KINX | 2024 | [link](https://kinx.net/?lang=en) | KINX is an Internet infrastructure service provider and will use kamaji for its new [Managed Kubernetes Service](https://kinx.net/service/cloud/kubernetes/intro/?lang=en). |
|
||||
| Vendor | Netsons | 2023 | [link](https://www.netsons.com) | Netsons is an Italian hosting and cloud provider and uses Kamaji in its [Managed Kubernetes](https://www.netsons.com/kubernetes) offering. |
|
||||
| R&D | Orange | 2024 | [link](https://gitlab.com/Orange-OpenSource/kanod) | Orange is a French telecommunications company using Kamaji for experimental research purpose, with Kanod research solution. |
|
||||
| Vendor | Platform9 | 2024 | [link](https://elasticmachinepool.com) | Platform9 uses Kamaji in its offering - Elastic Machine Pool, which is a tool for optimizing the cost of running kubernetes clusters in EKS. |
|
||||
| Vendor | Qumulus | 2024 | [link](https://www.qumulus.io) | Qumulus is a cloud provider and plans to use Kamaji for it's hosted Kubernetes service |
|
||||
| End-user | sevensphere | 2023 | [link](https://www.sevensphere.io) | Sevensphere provides consulting services for end-user companies / cloud providers and uses Kamaji for designing cloud/on-premises Kubernetes-as-a-Service platform. |
|
||||
| End-user | Sicuro Tech Lab | 2024 | [link](https://sicurotechlab.it/) | Sicuro Tech Lab offers cloud infrastructure for Web Agencies and uses kamaji to provide managed k8s services. |
|
||||
|
||||
31
Makefile
31
Makefile
@@ -3,7 +3,21 @@
|
||||
# To re-generate a bundle for another specific version without changing the standard setup, you can:
|
||||
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
|
||||
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
|
||||
VERSION ?= v1.0.0
|
||||
VERSION ?= $(or $(shell git describe --abbrev=0 --tags 2>/dev/null),$(GIT_HEAD_COMMIT))
|
||||
|
||||
# ENVTEST_K8S_VERSION specifies the Kubernetes version to be used
|
||||
# during testing with the envtest environment. This ensures that
|
||||
# the tests run against the correct API and behavior for the
|
||||
# specific Kubernetes release being targeted (v1.31.0 in this case).
|
||||
ENVTEST_K8S_VERSION = 1.31.0
|
||||
|
||||
# ENVTEST_VERSION defines the version of the setup-envtest binary
|
||||
# used to manage and download the Kubernetes binaries (like etcd,
|
||||
# kube-apiserver, and kubectl) required for testing. This version
|
||||
# ensures compatibility with the selected Kubernetes version and
|
||||
# must align closely with recent releases (release-0.19 is chosen here).
|
||||
# Mismatches between these versions could result in compatibility issues.
|
||||
ENVTEST_VERSION ?= release-0.19
|
||||
|
||||
# Image URL to use all building/pushing image targets
|
||||
CONTAINER_REPOSITORY ?= docker.io/clastix/kamaji
|
||||
@@ -34,6 +48,7 @@ HELM ?= $(LOCALBIN)/helm
|
||||
KIND ?= $(LOCALBIN)/kind
|
||||
KO ?= $(LOCALBIN)/ko
|
||||
YQ ?= $(LOCALBIN)/yq
|
||||
ENVTEST ?= $(LOCALBIN)/setup-envtest
|
||||
|
||||
all: build
|
||||
|
||||
@@ -88,13 +103,18 @@ $(CONTROLLER_GEN): $(LOCALBIN)
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
|
||||
$(GOLANGCI_LINT): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/golangci-lint || GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.54.2
|
||||
test -s $(LOCALBIN)/golangci-lint || GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.2
|
||||
|
||||
.PHONY: apidocs-gen
|
||||
apidocs-gen: $(APIDOCS_GEN) ## Download crdoc locally if necessary.
|
||||
$(APIDOCS_GEN): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/crdoc || GOBIN=$(LOCALBIN) go install fybrik.io/crdoc@latest
|
||||
|
||||
.PHONY: envtest
|
||||
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
|
||||
$(ENVTEST): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@$(ENVTEST_VERSION)
|
||||
|
||||
##@ Development
|
||||
|
||||
rbac: controller-gen yq
|
||||
@@ -121,9 +141,10 @@ generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and
|
||||
golint: golangci-lint ## Linting the code according to the styling guide.
|
||||
$(GOLANGCI_LINT) run -c .golangci.yml
|
||||
|
||||
## Run unit tests (all tests except E2E).
|
||||
.PHONY: test
|
||||
test: ## Run unit tests (all tests except E2E).
|
||||
@go test \
|
||||
test: envtest ginkgo
|
||||
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" $(GINKGO) -r -v --trace \
|
||||
./api/... \
|
||||
./cmd/... \
|
||||
./internal/... \
|
||||
@@ -224,7 +245,7 @@ env:
|
||||
e2e: env build load helm ginkgo cert-manager ## Create a KinD cluster, install Kamaji on it and run the test suite.
|
||||
$(HELM) repo add clastix https://clastix.github.io/charts
|
||||
$(HELM) dependency build ./charts/kamaji
|
||||
$(HELM) upgrade --debug --install kamaji ./charts/kamaji --create-namespace --namespace kamaji-system --set "image.pullPolicy=Never" --set "telemetry.disabled=true"
|
||||
$(HELM) upgrade --debug --install kamaji ./charts/kamaji --create-namespace --namespace kamaji-system --set "image.tag=$(VERSION)" --set "image.pullPolicy=Never" --set "telemetry.disabled=true"
|
||||
$(MAKE) datastores
|
||||
$(GINKGO) -v ./e2e
|
||||
|
||||
|
||||
55
api/v1alpha1/suite_test.go
Normal file
55
api/v1alpha1/suite_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
)
|
||||
|
||||
var (
|
||||
cfg *rest.Config
|
||||
k8sClient client.Client
|
||||
testEnv *envtest.Environment
|
||||
)
|
||||
|
||||
func TestAPIs(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "TenantControlPlane Suite")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
By("bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{
|
||||
filepath.Join("..", "..", "charts", "kamaji", "crds"),
|
||||
// filepath.Join("../..", "chart", "kamaji", "crds"),
|
||||
},
|
||||
}
|
||||
|
||||
var err error
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cfg).ToNot(BeNil())
|
||||
|
||||
err = AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(k8sClient).ToNot(BeNil())
|
||||
})
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
By("tearing down the test environment")
|
||||
err := testEnv.Stop()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
@@ -8,5 +8,5 @@ package v1alpha1
|
||||
// +kubebuilder:object:generate=false
|
||||
type KubeadmConfigChecksumDependant interface {
|
||||
GetChecksum() string
|
||||
SetChecksum(string)
|
||||
SetChecksum(checksum string)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (in KubeadmPhaseStatus) GetChecksum() string {
|
||||
func (in *KubeadmPhaseStatus) GetChecksum() string {
|
||||
return in.Checksum
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,19 @@ import (
|
||||
|
||||
// NetworkProfileSpec defines the desired state of NetworkProfile.
|
||||
type NetworkProfileSpec struct {
|
||||
// LoadBalancerSourceRanges restricts the IP ranges that can access
|
||||
// the LoadBalancer type Service. This field defines a list of IP
|
||||
// address ranges (in CIDR format) that are allowed to access the service.
|
||||
// If left empty, the service will allow traffic from all IP ranges (0.0.0.0/0).
|
||||
// This feature is useful for restricting access to API servers or services
|
||||
// to specific networks for security purposes.
|
||||
// Example: {"192.168.1.0/24", "10.0.0.0/8"}
|
||||
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"`
|
||||
// Specify the LoadBalancer class in case of multiple load balancer implementations.
|
||||
// Field supported only for Tenant Control Plane instances exposed using a LoadBalancer Service.
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="LoadBalancerClass is immutable"
|
||||
LoadBalancerClass *string `json:"loadBalancerClass,omitempty"`
|
||||
// Address where API server of will be exposed.
|
||||
// In case of LoadBalancer Service, this can be empty in order to use the exposed IP provided by the cloud controller manager.
|
||||
Address string `json:"address,omitempty"`
|
||||
@@ -28,13 +41,16 @@ type NetworkProfileSpec struct {
|
||||
// CertSANs sets extra Subject Alternative Names (SANs) for the API Server signing certificate.
|
||||
// Use this field to add additional hostnames when exposing the Tenant Control Plane with third solutions.
|
||||
CertSANs []string `json:"certSANs,omitempty"`
|
||||
// Kubernetes Service
|
||||
// CIDR for Kubernetes Services: if empty, defaulted to 10.96.0.0/16.
|
||||
//+kubebuilder:default="10.96.0.0/16"
|
||||
ServiceCIDR string `json:"serviceCidr,omitempty"`
|
||||
// CIDR for Kubernetes Pods
|
||||
// CIDR for Kubernetes Pods: if empty, defaulted to 10.244.0.0/16.
|
||||
//+kubebuilder:default="10.244.0.0/16"
|
||||
PodCIDR string `json:"podCidr,omitempty"`
|
||||
//+kubebuilder:default={"10.96.0.10"}
|
||||
// The DNS Service for internal resolution, it must match the Service CIDR.
|
||||
// In case of an empty value, it is automatically computed according to the Service CIDR, e.g.:
|
||||
// Service CIDR 10.96.0.0/16, the resulting DNS Service IP will be 10.96.0.10 for IPv4,
|
||||
// for IPv6 from the CIDR 2001:db8:abcd::/64 the resulting DNS Service IP will be 2001:db8:abcd::10.
|
||||
DNSServiceIPs []string `json:"dnsServiceIPs,omitempty"`
|
||||
}
|
||||
|
||||
@@ -256,9 +272,15 @@ type AddonsSpec struct {
|
||||
// TenantControlPlaneSpec defines the desired state of TenantControlPlane.
|
||||
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.dataStore) || has(self.dataStore)", message="unsetting the dataStore is not supported"
|
||||
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.dataStoreSchema) || has(self.dataStoreSchema)", message="unsetting the dataStoreSchema is not supported"
|
||||
// +kubebuilder:validation:XValidation:rule="!has(self.networkProfile.loadBalancerSourceRanges) || (size(self.networkProfile.loadBalancerSourceRanges) == 0 || self.controlPlane.service.serviceType == 'LoadBalancer')", message="LoadBalancer source ranges are supported only with LoadBalancer service type"
|
||||
// +kubebuilder:validation:XValidation:rule="!has(self.networkProfile.loadBalancerClass) || self.controlPlane.service.serviceType == 'LoadBalancer'", message="LoadBalancerClass is supported only with LoadBalancer service type"
|
||||
// +kubebuilder:validation:XValidation:rule="self.controlPlane.service.serviceType != 'LoadBalancer' || (oldSelf.controlPlane.service.serviceType != 'LoadBalancer' && self.controlPlane.service.serviceType == 'LoadBalancer') || has(self.networkProfile.loadBalancerClass) == has(oldSelf.networkProfile.loadBalancerClass)",message="LoadBalancerClass cannot be set or unset at runtime"
|
||||
|
||||
type TenantControlPlaneSpec struct {
|
||||
// DataStore allows to specify a DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane.
|
||||
// This parameter is optional and acts as an override over the default one which is used by the Kamaji Operator.
|
||||
// DataStore specifies the DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane.
|
||||
// When Kamaji runs with the default DataStore flag, all empty values will inherit the default value.
|
||||
// By leaving it empty and running Kamaji with no default DataStore flag, it is possible to achieve automatic assignment to a specific DataStore object.
|
||||
//
|
||||
// Migration from one DataStore to another backed by the same Driver is possible. See: https://kamaji.clastix.io/guides/datastore-migration/
|
||||
// Migration from one DataStore to another backed by a different Driver is not supported.
|
||||
DataStore string `json:"dataStore,omitempty"`
|
||||
|
||||
78
api/v1alpha1/tenantcontrolplane_types_test.go
Normal file
78
api/v1alpha1/tenantcontrolplane_types_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
var _ = Describe("Cluster controller", func() {
|
||||
var (
|
||||
ctx context.Context
|
||||
tcp *TenantControlPlane
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
ctx = context.Background() //nolint:fatcontext
|
||||
tcp = &TenantControlPlane{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "tcp",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: TenantControlPlaneSpec{},
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
if err := k8sClient.Delete(ctx, tcp); err != nil && !apierrors.IsNotFound(err) {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
})
|
||||
|
||||
Context("LoadBalancer Source Ranges", func() {
|
||||
It("allows creation when no CIDR ranges are provided", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = ServiceTypeLoadBalancer
|
||||
|
||||
err := k8sClient.Create(ctx, tcp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("allows creation with an explicitly empty CIDR list", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = ServiceTypeLoadBalancer
|
||||
tcp.Spec.NetworkProfile.LoadBalancerSourceRanges = []string{}
|
||||
|
||||
err := k8sClient.Create(ctx, tcp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("allows creation when service type is not LoadBalancer and it has an empty CIDR list", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = ServiceTypeNodePort
|
||||
|
||||
err := k8sClient.Create(ctx, tcp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("allows CIDR ranges when service type is LoadBalancer", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = ServiceTypeLoadBalancer
|
||||
tcp.Spec.NetworkProfile.LoadBalancerSourceRanges = []string{"192.168.0.0/24"}
|
||||
|
||||
err := k8sClient.Create(ctx, tcp)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("denies CIDR ranges when service type is not LoadBalancer", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = ServiceTypeNodePort
|
||||
tcp.Spec.NetworkProfile.LoadBalancerSourceRanges = []string{"192.168.0.0/24"}
|
||||
|
||||
err := k8sClient.Create(ctx, tcp)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("LoadBalancer source ranges are supported only with LoadBalancer service type"))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1105,6 +1105,11 @@ func (in *KubernetesVersion) DeepCopy() *KubernetesVersion {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *NetworkProfileSpec) DeepCopyInto(out *NetworkProfileSpec) {
|
||||
*out = *in
|
||||
if in.LoadBalancerSourceRanges != nil {
|
||||
in, out := &in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.CertSANs != nil {
|
||||
in, out := &in.CertSANs, &out.CertSANs
|
||||
*out = make([]string, len(*in))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
- name: kamaji-etcd
|
||||
repository: https://clastix.github.io/charts
|
||||
version: 0.8.0
|
||||
digest: sha256:525b0eb2b5bae709d62de9328312d42c54b5219c6df67061de0da79eeca04fb3
|
||||
generated: "2024-08-25T08:44:24.92211307+02:00"
|
||||
version: 0.8.1
|
||||
digest: sha256:381d8ef9619c2daeea37e40c6a9772ae3e5cee80887148879db04e887d5364ad
|
||||
generated: "2024-10-25T19:28:40.880766186+02:00"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: v1.0.0
|
||||
appVersion: v0.0.0
|
||||
description: Kamaji is the Hosted Control Plane Manager for Kubernetes.
|
||||
home: https://github.com/clastix/kamaji
|
||||
icon: https://github.com/clastix/kamaji/raw/master/assets/logo-colored.png
|
||||
@@ -17,11 +17,11 @@ name: kamaji
|
||||
sources:
|
||||
- https://github.com/clastix/kamaji
|
||||
type: application
|
||||
version: 2.0.0
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
- name: kamaji-etcd
|
||||
repository: https://clastix.github.io/charts
|
||||
version: ">=0.7.0"
|
||||
version: ">=0.8.1"
|
||||
condition: kamaji-etcd.deploy
|
||||
annotations:
|
||||
catalog.cattle.io/certified: partner
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# kamaji
|
||||
|
||||
  
|
||||
  
|
||||
|
||||
Kamaji is the Hosted Control Plane Manager for Kubernetes.
|
||||
|
||||
@@ -22,7 +22,7 @@ Kubernetes: `>=1.21.0-0`
|
||||
|
||||
| Repository | Name | Version |
|
||||
|------------|------|---------|
|
||||
| https://clastix.github.io/charts | kamaji-etcd | >=0.7.0 |
|
||||
| https://clastix.github.io/charts | kamaji-etcd | >=0.8.1 |
|
||||
|
||||
[Kamaji](https://github.com/clastix/kamaji) requires a [multi-tenant `etcd`](https://github.com/clastix/kamaji-internal/blob/master/deploy/getting-started-with-kamaji.md#setup-internal-multi-tenant-etcd) cluster.
|
||||
This Helm Chart starting from v0.1.1 provides the installation of an internal `etcd` in order to streamline the local test. If you'd like to use an externally managed etcd instance, you can specify the overrides and by setting the value `etcd.deploy=false`.
|
||||
@@ -70,7 +70,7 @@ Here the values you can override:
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| affinity | object | `{}` | Kubernetes affinity rules to apply to Kamaji controller pods |
|
||||
| defaultDatastoreName | string | `"default"` | Specify the default DataStore name for the Kamaji instance. |
|
||||
| defaultDatastoreName | string | `"default"` | If specified, all the Kamaji instances with an unassigned DataStore will inherit this default value. |
|
||||
| extraArgs | list | `[]` | A list of extra arguments to add to the kamaji controller default ones |
|
||||
| fullnameOverride | string | `""` | |
|
||||
| healthProbeBindAddress | string | `":8081"` | The address the probe endpoint binds to. (default ":8081") |
|
||||
|
||||
@@ -66,7 +66,6 @@ spec:
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: TenantControlPlaneSpec defines the desired state of TenantControlPlane.
|
||||
properties:
|
||||
addons:
|
||||
description: Addons contain which addons are enabled
|
||||
@@ -6413,8 +6412,10 @@ spec:
|
||||
type: object
|
||||
dataStore:
|
||||
description: |-
|
||||
DataStore allows to specify a DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane.
|
||||
This parameter is optional and acts as an override over the default one which is used by the Kamaji Operator.
|
||||
DataStore specifies the DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane.
|
||||
When Kamaji runs with the default DataStore flag, all empty values will inherit the default value.
|
||||
By leaving it empty and running Kamaji with no default DataStore flag, it is possible to achieve automatic assignment to a specific DataStore object.
|
||||
|
||||
Migration from one DataStore to another backed by the same Driver is possible. See: https://kamaji.clastix.io/guides/datastore-migration/
|
||||
Migration from one DataStore to another backed by a different Driver is not supported.
|
||||
type: string
|
||||
@@ -6559,14 +6560,38 @@ spec:
|
||||
- message: changing the cluster domain is not supported
|
||||
rule: self == oldSelf
|
||||
dnsServiceIPs:
|
||||
default:
|
||||
- 10.96.0.10
|
||||
description: |-
|
||||
The DNS Service for internal resolution, it must match the Service CIDR.
|
||||
In case of an empty value, it is automatically computed according to the Service CIDR, e.g.:
|
||||
Service CIDR 10.96.0.0/16, the resulting DNS Service IP will be 10.96.0.10 for IPv4,
|
||||
for IPv6 from the CIDR 2001:db8:abcd::/64 the resulting DNS Service IP will be 2001:db8:abcd::10.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
loadBalancerClass:
|
||||
description: |-
|
||||
Specify the LoadBalancer class in case of multiple load balancer implementations.
|
||||
Field supported only for Tenant Control Plane instances exposed using a LoadBalancer Service.
|
||||
minLength: 1
|
||||
type: string
|
||||
x-kubernetes-validations:
|
||||
- message: LoadBalancerClass is immutable
|
||||
rule: self == oldSelf
|
||||
loadBalancerSourceRanges:
|
||||
description: |-
|
||||
LoadBalancerSourceRanges restricts the IP ranges that can access
|
||||
the LoadBalancer type Service. This field defines a list of IP
|
||||
address ranges (in CIDR format) that are allowed to access the service.
|
||||
If left empty, the service will allow traffic from all IP ranges (0.0.0.0/0).
|
||||
This feature is useful for restricting access to API servers or services
|
||||
to specific networks for security purposes.
|
||||
Example: {"192.168.1.0/24", "10.0.0.0/8"}
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
podCidr:
|
||||
default: 10.244.0.0/16
|
||||
description: CIDR for Kubernetes Pods
|
||||
description: 'CIDR for Kubernetes Pods: if empty, defaulted to 10.244.0.0/16.'
|
||||
type: string
|
||||
port:
|
||||
default: 6443
|
||||
@@ -6575,7 +6600,7 @@ spec:
|
||||
type: integer
|
||||
serviceCidr:
|
||||
default: 10.96.0.0/16
|
||||
description: Kubernetes Service
|
||||
description: 'CIDR for Kubernetes Services: if empty, defaulted to 10.96.0.0/16.'
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
@@ -6587,6 +6612,12 @@ spec:
|
||||
rule: '!has(oldSelf.dataStore) || has(self.dataStore)'
|
||||
- message: unsetting the dataStoreSchema is not supported
|
||||
rule: '!has(oldSelf.dataStoreSchema) || has(self.dataStoreSchema)'
|
||||
- message: LoadBalancer source ranges are supported only with LoadBalancer service type
|
||||
rule: '!has(self.networkProfile.loadBalancerSourceRanges) || (size(self.networkProfile.loadBalancerSourceRanges) == 0 || self.controlPlane.service.serviceType == ''LoadBalancer'')'
|
||||
- message: LoadBalancerClass is supported only with LoadBalancer service type
|
||||
rule: '!has(self.networkProfile.loadBalancerClass) || self.controlPlane.service.serviceType == ''LoadBalancer'''
|
||||
- message: LoadBalancerClass cannot be set or unset at runtime
|
||||
rule: self.controlPlane.service.serviceType != 'LoadBalancer' || (oldSelf.controlPlane.service.serviceType != 'LoadBalancer' && self.controlPlane.service.serviceType == 'LoadBalancer') || has(self.networkProfile.loadBalancerClass) == has(oldSelf.networkProfile.loadBalancerClass)
|
||||
status:
|
||||
description: TenantControlPlaneStatus defines the observed state of TenantControlPlane.
|
||||
properties:
|
||||
|
||||
@@ -33,8 +33,9 @@ spec:
|
||||
- --leader-elect
|
||||
- --metrics-bind-address={{ .Values.metricsBindAddress }}
|
||||
- --tmp-directory={{ .Values.temporaryDirectoryPath }}
|
||||
{{- $datastoreName := .Values.defaultDatastoreName | required ".Values.defaultDatastoreName is required!" }}
|
||||
- --datastore={{ $datastoreName }}
|
||||
{{- if not (eq .Values.defaultDatastoreName "") }}
|
||||
- --datastore={{ .Values.defaultDatastoreName }}
|
||||
{{- end }}
|
||||
{{- if .Values.telemetry.disabled }}
|
||||
- --disable-telemetry
|
||||
{{- end }}
|
||||
|
||||
@@ -95,7 +95,7 @@ loggingDevel:
|
||||
# -- Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false)
|
||||
enable: false
|
||||
|
||||
# -- Specify the default DataStore name for the Kamaji instance.
|
||||
# -- If specified, all the Kamaji instances with an unassigned DataStore will inherit this default value.
|
||||
defaultDatastoreName: default
|
||||
|
||||
kamaji-etcd:
|
||||
|
||||
@@ -41,21 +41,22 @@ import (
|
||||
func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
// CLI flags
|
||||
var (
|
||||
metricsBindAddress string
|
||||
healthProbeBindAddress string
|
||||
leaderElect bool
|
||||
tmpDirectory string
|
||||
kineImage string
|
||||
controllerReconcileTimeout time.Duration
|
||||
cacheResyncPeriod time.Duration
|
||||
datastore string
|
||||
managerNamespace string
|
||||
managerServiceAccountName string
|
||||
managerServiceName string
|
||||
webhookCABundle []byte
|
||||
migrateJobImage string
|
||||
maxConcurrentReconciles int
|
||||
disableTelemetry bool
|
||||
metricsBindAddress string
|
||||
healthProbeBindAddress string
|
||||
leaderElect bool
|
||||
tmpDirectory string
|
||||
kineImage string
|
||||
controllerReconcileTimeout time.Duration
|
||||
cacheResyncPeriod time.Duration
|
||||
datastore string
|
||||
managerNamespace string
|
||||
managerServiceAccountName string
|
||||
managerServiceName string
|
||||
webhookCABundle []byte
|
||||
migrateJobImage string
|
||||
maxConcurrentReconciles int
|
||||
disableTelemetry bool
|
||||
certificateExpirationDeadline time.Duration
|
||||
|
||||
webhookCAPath string
|
||||
)
|
||||
@@ -67,15 +68,19 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
Short: "Start the Kamaji Kubernetes Operator",
|
||||
SilenceErrors: false,
|
||||
SilenceUsage: true,
|
||||
PreRunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
PreRunE: func(cmd *cobra.Command, _ []string) (err error) {
|
||||
// Avoid to pollute Kamaji stdout with useless details by the underlying klog implementations
|
||||
klog.SetOutput(io.Discard)
|
||||
klog.LogToStderr(false)
|
||||
|
||||
if err = cmdutils.CheckFlags(cmd.Flags(), []string{"kine-image", "datastore", "migrate-image", "tmp-directory", "pod-namespace", "webhook-service-name", "serviceaccount-name", "webhook-ca-path"}...); err != nil {
|
||||
if err = cmdutils.CheckFlags(cmd.Flags(), []string{"kine-image", "migrate-image", "tmp-directory", "pod-namespace", "webhook-service-name", "serviceaccount-name", "webhook-ca-path"}...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if certificateExpirationDeadline < 24*time.Hour {
|
||||
return fmt.Errorf("certificate expiration deadline must be at least 24 hours")
|
||||
}
|
||||
|
||||
if webhookCABundle, err = os.ReadFile(webhookCAPath); err != nil {
|
||||
return fmt.Errorf("unable to read webhook CA: %w", err)
|
||||
}
|
||||
@@ -90,7 +95,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(*cobra.Command, []string) error {
|
||||
setupLog := ctrl.Log.WithName("setup")
|
||||
|
||||
setupLog.Info(fmt.Sprintf("Kamaji version %s %s%s", internal.GitTag, internal.GitCommit, internal.GitDirty))
|
||||
@@ -186,7 +191,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
if err = (&controllers.CertificateLifecycle{Channel: certChannel}).SetupWithManager(mgr); err != nil {
|
||||
if err = (&controllers.CertificateLifecycle{Channel: certChannel, Deadline: certificateExpirationDeadline}).SetupWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "CertificateLifecycle")
|
||||
|
||||
return err
|
||||
@@ -229,6 +234,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
},
|
||||
},
|
||||
handlers.TenantControlPlaneServiceCIDR{},
|
||||
handlers.TenantControlPlaneLoadBalancerSourceRanges{},
|
||||
},
|
||||
routes.TenantControlPlaneTelemetry{}: {
|
||||
handlers.TenantControlPlaneTelemetry{
|
||||
@@ -298,7 +304,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
cmd.Flags().BoolVar(&leaderElect, "leader-elect", true, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
|
||||
cmd.Flags().StringVar(&tmpDirectory, "tmp-directory", "/tmp/kamaji", "Directory which will be used to work with temporary files.")
|
||||
cmd.Flags().StringVar(&kineImage, "kine-image", "rancher/kine:v0.11.10-amd64", "Container image along with tag to use for the Kine sidecar container (used only if etcd-storage-type is set to one of kine strategies).")
|
||||
cmd.Flags().StringVar(&datastore, "datastore", "etcd", "The default DataStore that should be used by Kamaji to setup the required storage.")
|
||||
cmd.Flags().StringVar(&datastore, "datastore", "", "Optional, the default DataStore that should be used by Kamaji to setup the required storage of Tenant Control Planes with undeclared DataStore.")
|
||||
cmd.Flags().StringVar(&migrateJobImage, "migrate-image", fmt.Sprintf("clastix/kamaji:%s", internal.GitTag), "Specify the container image to launch when a TenantControlPlane is migrated to a new datastore.")
|
||||
cmd.Flags().IntVar(&maxConcurrentReconciles, "max-concurrent-tcp-reconciles", 1, "Specify the number of workers for the Tenant Control Plane controller (beware of CPU consumption)")
|
||||
cmd.Flags().StringVar(&managerNamespace, "pod-namespace", os.Getenv("POD_NAMESPACE"), "The Kubernetes Namespace on which the Operator is running in, required for the TenantControlPlane migration jobs.")
|
||||
@@ -308,6 +314,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
cmd.Flags().DurationVar(&controllerReconcileTimeout, "controller-reconcile-timeout", 30*time.Second, "The reconciliation request timeout before the controller withdraw the external resource calls, such as dealing with the Datastore, or the Tenant Control Plane API endpoint.")
|
||||
cmd.Flags().DurationVar(&cacheResyncPeriod, "cache-resync-period", 10*time.Hour, "The controller-runtime.Manager cache resync period.")
|
||||
cmd.Flags().BoolVar(&disableTelemetry, "disable-telemetry", false, "Disable the analytics traces collection.")
|
||||
cmd.Flags().DurationVar(&certificateExpirationDeadline, "certificate-expiration-deadline", 24*time.Hour, "Define the deadline upon certificate expiration to start the renewal process, cannot be less than a 24 hours.")
|
||||
|
||||
cobra.OnInitialize(func() {
|
||||
viper.AutomaticEnv()
|
||||
|
||||
@@ -31,7 +31,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
Use: "migrate",
|
||||
Short: "Migrate the data of a TenantControlPlane to another compatible DataStore",
|
||||
SilenceUsage: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(*cobra.Command, []string) error {
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancelFn()
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "kamaji",
|
||||
Short: "Build and operate Kubernetes at scale with a fraction of operational burden.",
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
PersistentPreRun: func(*cobra.Command, []string) {
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
utilruntime.Must(kamajiv1alpha1.AddToScheme(scheme))
|
||||
utilruntime.Must(appsv1.RegisterDefaults(scheme))
|
||||
|
||||
@@ -30,8 +30,10 @@ import (
|
||||
)
|
||||
|
||||
type CertificateLifecycle struct {
|
||||
Channel CertificateChannel
|
||||
client client.Client
|
||||
Channel CertificateChannel
|
||||
Deadline time.Duration
|
||||
|
||||
client client.Client
|
||||
}
|
||||
|
||||
func (s *CertificateLifecycle) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
|
||||
@@ -76,7 +78,7 @@ func (s *CertificateLifecycle) Reconcile(ctx context.Context, request reconcile.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
deadline := time.Now().AddDate(0, 0, 1)
|
||||
deadline := time.Now().Add(s.Deadline)
|
||||
|
||||
if deadline.After(crt.NotAfter) {
|
||||
logger.Info("certificate near expiration, must be rotated")
|
||||
|
||||
@@ -101,7 +101,7 @@ func (r *DataStore) SetupWithManager(mgr controllerruntime.Manager) error {
|
||||
CreateFunc: func(_ context.Context, createEvent event.TypedCreateEvent[client.Object], w workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
enqueueFn(createEvent.Object.(*kamajiv1alpha1.TenantControlPlane), w)
|
||||
},
|
||||
UpdateFunc: func(ctx context.Context, updateEvent event.TypedUpdateEvent[client.Object], w workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
UpdateFunc: func(_ context.Context, updateEvent event.TypedUpdateEvent[client.Object], w workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
enqueueFn(updateEvent.ObjectOld.(*kamajiv1alpha1.TenantControlPlane), w)
|
||||
enqueueFn(updateEvent.ObjectNew.(*kamajiv1alpha1.TenantControlPlane), w)
|
||||
},
|
||||
|
||||
@@ -182,7 +182,7 @@ func (m *Manager) Reconcile(ctx context.Context, request reconcile.Request) (res
|
||||
Metrics: metricsserver.Options{
|
||||
BindAddress: "0",
|
||||
},
|
||||
NewClient: func(config *rest.Config, options client.Options) (client.Client, error) {
|
||||
NewClient: func(config *rest.Config, _ client.Options) (client.Client, error) {
|
||||
return client.New(config, client.Options{
|
||||
Scheme: m.client.Scheme(),
|
||||
})
|
||||
|
||||
@@ -122,6 +122,12 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
// Retrieving the DataStore to use for the current reconciliation
|
||||
ds, err := r.dataStore(ctx, tenantControlPlane)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrMissingDataStore) {
|
||||
log.Info(err.Error())
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
}
|
||||
|
||||
log.Error(err, "cannot retrieve the DataStore for the given instance")
|
||||
|
||||
return ctrl.Result{}, err
|
||||
@@ -300,18 +306,23 @@ func (r *TenantControlPlaneReconciler) RemoveFinalizer(ctx context.Context, tena
|
||||
return r.Client.Update(ctx, tenantControlPlane)
|
||||
}
|
||||
|
||||
var ErrMissingDataStore = errors.New("the Tenant Control Plane doesn't have a DataStore assigned, and Kamaji is running with no default DataStore fallback")
|
||||
|
||||
// dataStore retrieves the override DataStore for the given Tenant Control Plane if specified,
|
||||
// otherwise fallback to the default one specified in the Kamaji setup.
|
||||
func (r *TenantControlPlaneReconciler) dataStore(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (*kamajiv1alpha1.DataStore, error) {
|
||||
dataStoreName := tenantControlPlane.Spec.DataStore
|
||||
if len(dataStoreName) == 0 {
|
||||
dataStoreName = r.Config.DefaultDataStoreName
|
||||
if tenantControlPlane.Spec.DataStore == "" && r.Config.DefaultDataStoreName == "" {
|
||||
return nil, ErrMissingDataStore
|
||||
}
|
||||
|
||||
ds := &kamajiv1alpha1.DataStore{}
|
||||
if err := r.Client.Get(ctx, k8stypes.NamespacedName{Name: dataStoreName}, ds); err != nil {
|
||||
if tenantControlPlane.Spec.DataStore == "" {
|
||||
tenantControlPlane.Spec.DataStore = r.Config.DefaultDataStoreName
|
||||
}
|
||||
|
||||
var ds kamajiv1alpha1.DataStore
|
||||
if err := r.Client.Get(ctx, k8stypes.NamespacedName{Name: tenantControlPlane.Spec.DataStore}, &ds); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot retrieve *kamajiv1alpha.DataStore object")
|
||||
}
|
||||
|
||||
return ds, nil
|
||||
return &ds, nil
|
||||
}
|
||||
|
||||
@@ -94,7 +94,10 @@ k8s-126-576c775b5d-jmvlm 4/4 Running 0 50s
|
||||
The Kamaji operator will run a controller which processes all the Secrets to determine their expiration, both for the `kubeconfig`, as well as for the certificates.
|
||||
|
||||
The controller, named `CertificateLifecycle`, will extract the certificates from the _Secret_ objects notifying the `TenantControlPlaneReconciler` controller which will start a new certificate rotation.
|
||||
The rotation will occur the day before their expiration.
|
||||
By default, the rotation will occur the day before their expiration.
|
||||
|
||||
This rotation deadline can be dynamically configured using the Kamaji CLI flag `--certificate-expiration-deadline` using the Go _Duration_ syntax:
|
||||
e.g.: set the value `7d` to trigger the renewal a week before the effective expiration date.
|
||||
|
||||
> Nota Bene:
|
||||
>
|
||||
|
||||
@@ -782,7 +782,7 @@ TenantControlPlane is the Schema for the tenantcontrolplanes API.
|
||||
<td><b><a href="#tenantcontrolplanespec">spec</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
TenantControlPlaneSpec defines the desired state of TenantControlPlane.<br/>
|
||||
<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -800,7 +800,7 @@ TenantControlPlane is the Schema for the tenantcontrolplanes API.
|
||||
|
||||
|
||||
|
||||
TenantControlPlaneSpec defines the desired state of TenantControlPlane.
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
@@ -837,8 +837,10 @@ such as the number of Pod replicas, the Service resource, or the Ingress.<br/>
|
||||
<td><b>dataStore</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
DataStore allows to specify a DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane.
|
||||
This parameter is optional and acts as an override over the default one which is used by the Kamaji Operator.
|
||||
DataStore specifies the DataStore that should be used to store the Kubernetes data for the given Tenant Control Plane.
|
||||
When Kamaji runs with the default DataStore flag, all empty values will inherit the default value.
|
||||
By leaving it empty and running Kamaji with no default DataStore flag, it is possible to achieve automatic assignment to a specific DataStore object.
|
||||
|
||||
Migration from one DataStore to another backed by the same Driver is possible. See: https://kamaji.clastix.io/guides/datastore-migration/
|
||||
Migration from one DataStore to another backed by a different Driver is not supported.<br/>
|
||||
</td>
|
||||
@@ -13937,16 +13939,38 @@ Use this field to add additional hostnames when exposing the Tenant Control Plan
|
||||
<td><b>dnsServiceIPs</b></td>
|
||||
<td>[]string</td>
|
||||
<td>
|
||||
<br/>
|
||||
<br/>
|
||||
<i>Default</i>: [10.96.0.10]<br/>
|
||||
The DNS Service for internal resolution, it must match the Service CIDR.
|
||||
In case of an empty value, it is automatically computed according to the Service CIDR, e.g.:
|
||||
Service CIDR 10.96.0.0/16, the resulting DNS Service IP will be 10.96.0.10 for IPv4,
|
||||
for IPv6 from the CIDR 2001:db8:abcd::/64 the resulting DNS Service IP will be 2001:db8:abcd::10.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>loadBalancerClass</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Specify the LoadBalancer class in case of multiple load balancer implementations.
|
||||
Field supported only for Tenant Control Plane instances exposed using a LoadBalancer Service.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>loadBalancerSourceRanges</b></td>
|
||||
<td>[]string</td>
|
||||
<td>
|
||||
LoadBalancerSourceRanges restricts the IP ranges that can access
|
||||
the LoadBalancer type Service. This field defines a list of IP
|
||||
address ranges (in CIDR format) that are allowed to access the service.
|
||||
If left empty, the service will allow traffic from all IP ranges (0.0.0.0/0).
|
||||
This feature is useful for restricting access to API servers or services
|
||||
to specific networks for security purposes.
|
||||
Example: {"192.168.1.0/24", "10.0.0.0/8"}<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>podCidr</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
CIDR for Kubernetes Pods<br/>
|
||||
CIDR for Kubernetes Pods: if empty, defaulted to 10.244.0.0/16.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: 10.244.0.0/16<br/>
|
||||
</td>
|
||||
@@ -13965,7 +13989,7 @@ Use this field to add additional hostnames when exposing the Tenant Control Plan
|
||||
<td><b>serviceCidr</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Kubernetes Service<br/>
|
||||
CIDR for Kubernetes Services: if empty, defaulted to 10.96.0.0/16.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: 10.96.0.0/16<br/>
|
||||
</td>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//nolint:ginkgolinter
|
||||
package e2e
|
||||
|
||||
import (
|
||||
|
||||
117
go.mod
117
go.mod
@@ -1,14 +1,12 @@
|
||||
module github.com/clastix/kamaji
|
||||
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.22.1
|
||||
go 1.23
|
||||
|
||||
require (
|
||||
github.com/JamesStewy/go-mysqldump v0.2.2
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/clastix/kamaji-telemetry v1.0.0
|
||||
github.com/docker/docker v27.3.1+incompatible
|
||||
github.com/docker/docker v27.4.0+incompatible
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/go-pg/pg/v10 v10.13.0
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
@@ -17,27 +15,27 @@ require (
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/juju/mutex/v2 v2.0.0
|
||||
github.com/nats-io/nats.go v1.37.0
|
||||
github.com/onsi/ginkgo/v2 v2.20.2
|
||||
github.com/onsi/gomega v1.34.2
|
||||
github.com/onsi/ginkgo/v2 v2.22.0
|
||||
github.com/onsi/gomega v1.36.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/testcontainers/testcontainers-go v0.33.0
|
||||
go.etcd.io/etcd/api/v3 v3.5.16
|
||||
go.etcd.io/etcd/client/v3 v3.5.16
|
||||
github.com/testcontainers/testcontainers-go v0.34.0
|
||||
go.etcd.io/etcd/api/v3 v3.5.17
|
||||
go.etcd.io/etcd/client/v3 v3.5.17
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||
k8s.io/api v0.31.1
|
||||
k8s.io/apimachinery v0.31.1
|
||||
k8s.io/apiserver v0.31.1
|
||||
k8s.io/client-go v0.31.1
|
||||
k8s.io/api v0.31.3
|
||||
k8s.io/apimachinery v0.31.3
|
||||
k8s.io/apiserver v0.31.3
|
||||
k8s.io/client-go v0.31.3
|
||||
k8s.io/cluster-bootstrap v0.0.0
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kubelet v0.0.0
|
||||
k8s.io/kubernetes v1.31.1
|
||||
k8s.io/kubernetes v1.31.4
|
||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
|
||||
sigs.k8s.io/controller-runtime v0.19.0
|
||||
sigs.k8s.io/controller-runtime v0.19.3
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -60,7 +58,7 @@ require (
|
||||
github.com/coredns/corefile-migration v1.0.23 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
@@ -88,7 +86,7 @@ require (
|
||||
github.com/google/cel-go v0.20.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
@@ -138,6 +136,7 @@ require (
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
@@ -149,7 +148,7 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.17 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||
@@ -163,20 +162,20 @@ require (
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/crypto v0.28.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/oauth2 v0.21.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
golang.org/x/term v0.23.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/term v0.25.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
||||
google.golang.org/grpc v1.65.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // 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/ini.v1 v1.67.0 // indirect
|
||||
@@ -184,15 +183,15 @@ require (
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.31.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.31.3 // indirect
|
||||
k8s.io/cli-runtime v0.0.0 // indirect
|
||||
k8s.io/cloud-provider v0.0.0 // indirect
|
||||
k8s.io/component-base v0.31.1 // indirect
|
||||
k8s.io/component-helpers v0.31.1 // indirect
|
||||
k8s.io/controller-manager v0.31.1 // indirect
|
||||
k8s.io/cri-api v0.31.1 // indirect
|
||||
k8s.io/component-base v0.31.3 // indirect
|
||||
k8s.io/component-helpers v0.31.3 // indirect
|
||||
k8s.io/controller-manager v0.31.3 // indirect
|
||||
k8s.io/cri-api v0.31.3 // indirect
|
||||
k8s.io/cri-client v0.0.0 // indirect
|
||||
k8s.io/kms v0.31.1 // indirect
|
||||
k8s.io/kms v0.31.3 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
k8s.io/kube-proxy v0.0.0 // indirect
|
||||
k8s.io/system-validators v1.8.0 // indirect
|
||||
@@ -206,34 +205,34 @@ require (
|
||||
)
|
||||
|
||||
replace (
|
||||
k8s.io/api => k8s.io/api v0.31.1
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.31.1
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.31.1
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.31.1
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.31.1
|
||||
k8s.io/client-go => k8s.io/client-go v0.31.1
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.31.1
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.31.1
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.31.1
|
||||
k8s.io/component-base => k8s.io/component-base v0.31.1
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.31.1
|
||||
k8s.io/controller-manager => k8s.io/controller-manager v0.31.1
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.31.1
|
||||
k8s.io/cri-client => k8s.io/cri-client v0.31.1
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.31.1
|
||||
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.31.1
|
||||
k8s.io/endpointslice => k8s.io/endpointslice v0.31.1
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.31.1
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.31.1
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.31.1
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.31.1
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.31.1
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.31.1
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.31.1
|
||||
k8s.io/metrics => k8s.io/metrics v0.31.1
|
||||
k8s.io/mount-utils => k8s.io/mount-utils v0.31.1
|
||||
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.31.1
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.31.1
|
||||
k8s.io/api => k8s.io/api v0.31.3
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.31.3
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.31.3
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.31.3
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.31.3
|
||||
k8s.io/client-go => k8s.io/client-go v0.31.3
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.31.3
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.31.3
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.31.3
|
||||
k8s.io/component-base => k8s.io/component-base v0.31.3
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.31.3
|
||||
k8s.io/controller-manager => k8s.io/controller-manager v0.31.3
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.31.3
|
||||
k8s.io/cri-client => k8s.io/cri-client v0.31.3
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.31.3
|
||||
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.31.3
|
||||
k8s.io/endpointslice => k8s.io/endpointslice v0.31.3
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.31.3
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.31.3
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.31.3
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.31.3
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.31.3
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.31.3
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.31.3
|
||||
k8s.io/metrics => k8s.io/metrics v0.31.3
|
||||
k8s.io/mount-utils => k8s.io/mount-utils v0.31.3
|
||||
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.31.3
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.31.3
|
||||
)
|
||||
|
||||
replace github.com/JamesStewy/go-mysqldump => github.com/vtoma/go-mysqldump v1.0.0
|
||||
|
||||
136
go.sum
136
go.sum
@@ -47,8 +47,8 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
|
||||
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
|
||||
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
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=
|
||||
@@ -60,8 +60,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/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
|
||||
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v27.4.0+incompatible h1:I9z7sQ5qyzO0BfAb9IMOawRkAGxhYsidKiTMcm0DU+A=
|
||||
github.com/docker/docker v27.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@@ -151,8 +151,8 @@ 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.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA=
|
||||
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
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.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -262,10 +262,10 @@ github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
|
||||
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
|
||||
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
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 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
@@ -344,8 +344,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
|
||||
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/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
|
||||
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
|
||||
github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo=
|
||||
github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
@@ -377,14 +377,14 @@ github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFi
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||
go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0=
|
||||
go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E=
|
||||
go.etcd.io/etcd/api/v3 v3.5.17 h1:cQB8eb8bxwuxOilBpMJAEo8fAONyrdXTHUNcMd8yT1w=
|
||||
go.etcd.io/etcd/api/v3 v3.5.17/go.mod h1:d1hvkRuXkts6PmaYk2Vrgqbv7H4ADfAKhyJqHNLJCB4=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.17 h1:XxnDXAWq2pnxqx76ljWwiQ9jylbpC4rvkAeRVOUKKVw=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.17/go.mod h1:4DqK1TKacp/86nJk4FLQqo6Mn2vvQFBmruW3pP14H/w=
|
||||
go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8=
|
||||
go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg=
|
||||
go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE=
|
||||
go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50=
|
||||
go.etcd.io/etcd/client/v3 v3.5.17 h1:o48sINNeWz5+pjy/Z0+HKpj/xSnBkuVhVvXkjEXbqZY=
|
||||
go.etcd.io/etcd/client/v3 v3.5.17/go.mod h1:j2d4eXTHWkT2ClBgnnEPm/Wuu7jsqku41v9DZ3OtjQo=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA=
|
||||
@@ -424,8 +424,8 @@ 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.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
@@ -444,8 +444,8 @@ 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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
@@ -473,16 +473,16 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
|
||||
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
|
||||
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
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.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -494,8 +494,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
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.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -526,8 +526,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
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=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
@@ -555,44 +555,44 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU=
|
||||
k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI=
|
||||
k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40=
|
||||
k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ=
|
||||
k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U=
|
||||
k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
||||
k8s.io/apiserver v0.31.1 h1:Sars5ejQDCRBY5f7R3QFHdqN3s61nhkpaX8/k1iEw1c=
|
||||
k8s.io/apiserver v0.31.1/go.mod h1:lzDhpeToamVZJmmFlaLwdYZwd7zB+WYRYIboqA1kGxM=
|
||||
k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk=
|
||||
k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U=
|
||||
k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0=
|
||||
k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg=
|
||||
k8s.io/cloud-provider v0.31.1 h1:40b6AgDizwm5eWratZbqubTHMob25VWr6NX2Ei5TwZA=
|
||||
k8s.io/cloud-provider v0.31.1/go.mod h1:xAdkE7fdZdu9rKLuOZUMBfagu7bM+bas3iPux/2nLGg=
|
||||
k8s.io/cluster-bootstrap v0.31.1 h1:lS5aJi2r6WEKnjO5UhbYsz8e3xmEfoF4Hiob/gnB/Nk=
|
||||
k8s.io/cluster-bootstrap v0.31.1/go.mod h1:dxroRr4eQ0ekxis/kzGa1qODprQXAxQZrgDLfTk8Pug=
|
||||
k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8=
|
||||
k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w=
|
||||
k8s.io/component-helpers v0.31.1 h1:5hZUf3747atdgtR3gPntrG35rC2CkK7rYq2KUraz6Os=
|
||||
k8s.io/component-helpers v0.31.1/go.mod h1:ye0Gi8KzFNTfpIuzvVDtxJQMP/0Owkukf1vGf22Hl6U=
|
||||
k8s.io/controller-manager v0.31.1 h1:bwiy8y//EG5lJL2mdbOvZWrOgw2EXXIvwp95VYgoIis=
|
||||
k8s.io/controller-manager v0.31.1/go.mod h1:O440MSE6EI1AEVhB2Fc8FYqv6r8BHrSXjm5aj3886No=
|
||||
k8s.io/cri-api v0.31.1 h1:x0aI8yTI7Ho4c8tpuig8NwI/MRe+VhjiYyyebC2xphQ=
|
||||
k8s.io/cri-api v0.31.1/go.mod h1:Po3TMAYH/+KrZabi7QiwQI4a692oZcUOUThd/rqwxrI=
|
||||
k8s.io/cri-client v0.31.1 h1:w5D7BAhiaSVVDZqHs7YUZPpuUCybx8tCxfdBuDBw7zo=
|
||||
k8s.io/cri-client v0.31.1/go.mod h1:voVfZexZQwvlf/JD8w30sGN0k22LRcHRfCj7+m4kAXE=
|
||||
k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8=
|
||||
k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE=
|
||||
k8s.io/apiextensions-apiserver v0.31.3 h1:+GFGj2qFiU7rGCsA5o+p/rul1OQIq6oYpQw4+u+nciE=
|
||||
k8s.io/apiextensions-apiserver v0.31.3/go.mod h1:2DSpFhUZZJmn/cr/RweH1cEVVbzFw9YBu4T+U3mf1e4=
|
||||
k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4=
|
||||
k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
||||
k8s.io/apiserver v0.31.3 h1:+1oHTtCB+OheqFEz375D0IlzHZ5VeQKX1KGXnx+TTuY=
|
||||
k8s.io/apiserver v0.31.3/go.mod h1:PrxVbebxrxQPFhJk4powDISIROkNMKHibTg9lTRQ0Qg=
|
||||
k8s.io/cli-runtime v0.31.3 h1:fEQD9Xokir78y7pVK/fCJN090/iYNrLHpFbGU4ul9TI=
|
||||
k8s.io/cli-runtime v0.31.3/go.mod h1:Q2jkyTpl+f6AtodQvgDI8io3jrfr+Z0LyQBPJJ2Btq8=
|
||||
k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4=
|
||||
k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs=
|
||||
k8s.io/cloud-provider v0.31.3 h1:7C3CHQUUwnv/HWWVIaibZH06iPg663RYQ6C6Zy4FnO8=
|
||||
k8s.io/cloud-provider v0.31.3/go.mod h1:c7csKppoVb9Ej6upJ28AvHy4B3BtlRMzXfgezsDdPKw=
|
||||
k8s.io/cluster-bootstrap v0.31.3 h1:O1Yxk1bLaxZvmQCXLaJjj5iJD+lVMfJdRUuKgbUHPlA=
|
||||
k8s.io/cluster-bootstrap v0.31.3/go.mod h1:TI6TCsQQB4FfcryWgNO3SLXSKWBqHjx4DfyqSFwixj8=
|
||||
k8s.io/component-base v0.31.3 h1:DMCXXVx546Rfvhj+3cOm2EUxhS+EyztH423j+8sOwhQ=
|
||||
k8s.io/component-base v0.31.3/go.mod h1:xME6BHfUOafRgT0rGVBGl7TuSg8Z9/deT7qq6w7qjIU=
|
||||
k8s.io/component-helpers v0.31.3 h1:0zGPD2PrekhFWgmz85XxlMEl7dfhlKC1tERZDe3onQc=
|
||||
k8s.io/component-helpers v0.31.3/go.mod h1:HZ1HZx2TKXM7xSUV2cR9L5yDoyZPhhHQNaE3BPBLPUQ=
|
||||
k8s.io/controller-manager v0.31.3 h1:TyUav69iNYwLGwA96JDhusoZoGRdh1sdrLjXmWTcPgs=
|
||||
k8s.io/controller-manager v0.31.3/go.mod h1:yuhec+dbXmBz+4c32kxJxmcauB+1pjO2ttfYODWuv18=
|
||||
k8s.io/cri-api v0.31.3 h1:dsZXzrGrCEwHjsTDlAV7rutEplpMLY8bfNRMIqrtXjo=
|
||||
k8s.io/cri-api v0.31.3/go.mod h1:Po3TMAYH/+KrZabi7QiwQI4a692oZcUOUThd/rqwxrI=
|
||||
k8s.io/cri-client v0.31.3 h1:9ZwddaNJomqkTBYQqSmB+Ccns3beY4HyYDwmRtWTCJM=
|
||||
k8s.io/cri-client v0.31.3/go.mod h1:klbWiYkOatOQOkXOYZMZMGSTM8q9eC/efsYGuXcgPes=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kms v0.31.1 h1:cGLyV3cIwb0ovpP/jtyIe2mEuQ/MkbhmeBF2IYCA9Io=
|
||||
k8s.io/kms v0.31.1/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94=
|
||||
k8s.io/kms v0.31.3 h1:XCFmiJn5CCKs8xoOLpCmu42Ubm/KW85wNHybGFcSAYc=
|
||||
k8s.io/kms v0.31.3/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/kube-proxy v0.31.1 h1:jODw/T0LipsysugosF8JUqGNPiae5DLj3DHrK13iYDk=
|
||||
k8s.io/kube-proxy v0.31.1/go.mod h1:u5CXxT6M89GuyPbSTYGzsfuQj1yDoSkqAOvITFfhNXw=
|
||||
k8s.io/kubelet v0.31.1 h1:aAxwVxGzbbMKKk/FnSjvkN52K3LdHhjhzmYcyGBuE0c=
|
||||
k8s.io/kubelet v0.31.1/go.mod h1:8ZbexYHqUO946gXEfFmnMZiK2UKRGhk7LlGvJ71p2Ig=
|
||||
k8s.io/kubernetes v1.31.1 h1:1fcYJe8SAhtannpChbmnzHLwAV9Je99PrGaFtBvCxms=
|
||||
k8s.io/kubernetes v1.31.1/go.mod h1:/YGPL//Fb9mdv5vukvAQ7Xon+Bqwry52bmjTdORAw+Q=
|
||||
k8s.io/kube-proxy v0.31.3 h1:PL3xoM56fN+J20f+bH0sYztRPmDXknQmsqI9A5w7Q2U=
|
||||
k8s.io/kube-proxy v0.31.3/go.mod h1:qtO7335oLTJDOrAhLDlFvhYSPNzdNHWVN/aw21GhxmE=
|
||||
k8s.io/kubelet v0.31.3 h1:DIXRAmvVGp42mV2vpA1GCLU6oO8who0/vp3Oq6kSpbI=
|
||||
k8s.io/kubelet v0.31.3/go.mod h1:KSdbEfNy5VzqUlAHlytA/fH12s+sE1u8fb/8JY9sL/8=
|
||||
k8s.io/kubernetes v1.31.4 h1:VQDX52gTQnq8C/jCo48AQuDsWbWMh9XXxhQRDYjgakw=
|
||||
k8s.io/kubernetes v1.31.4/go.mod h1:9xmT2buyTYj8TRKwRae7FcuY8k5+xlxv7VivvO0KKfs=
|
||||
k8s.io/system-validators v1.8.0 h1:tq05tdO9zdJZnNF3SXrq6LE7Knc/KfJm5wk68467JDg=
|
||||
k8s.io/system-validators v1.8.0/go.mod h1:gP1Ky+R9wtrSiFbrpEPwWMeYz9yqyy1S/KOh0Vci7WI=
|
||||
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
|
||||
@@ -601,8 +601,8 @@ mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo=
|
||||
mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw=
|
||||
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/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=
|
||||
sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
|
||||
sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw=
|
||||
sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g=
|
||||
|
||||
@@ -1017,7 +1017,7 @@ func (d Deployment) templateLabels(ctx context.Context, tenantControlPlane *kama
|
||||
"component.kamaji.clastix.io/front-proxy-client-certificate": hash(ctx, tenantControlPlane.GetNamespace(), tenantControlPlane.Status.Certificates.FrontProxyClient.SecretName),
|
||||
"component.kamaji.clastix.io/service-account": hash(ctx, tenantControlPlane.GetNamespace(), tenantControlPlane.Status.Certificates.SA.SecretName),
|
||||
"component.kamaji.clastix.io/scheduler-kubeconfig": hash(ctx, tenantControlPlane.GetNamespace(), tenantControlPlane.Status.KubeConfig.Scheduler.SecretName),
|
||||
"component.kamaji.clastix.io/datastore": tenantControlPlane.Spec.DataStore,
|
||||
"component.kamaji.clastix.io/datastore": tenantControlPlane.Status.Storage.DataStoreName,
|
||||
}
|
||||
|
||||
return labels
|
||||
|
||||
@@ -13,9 +13,11 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
// CheckPublicAndPrivateKeyValidity checks if the given bytes for the private and public keys are valid.
|
||||
@@ -37,6 +39,39 @@ func CheckPublicAndPrivateKeyValidity(publicKey []byte, privateKey []byte) (bool
|
||||
return checkPublicKeys(privKey.PublicKey, *pubKey), nil
|
||||
}
|
||||
|
||||
// CheckCertificateSAN checks if the Kubernetes API Server certificate matches the SAN stored in the kubeadm:
|
||||
// it must check both IPs and DNS names, and returns a false if the required entry isn't available.
|
||||
// In case of removal of entries, this function returns true nevertheless to avoid reloading a Control Plane uselessly.
|
||||
func CheckCertificateSAN(certificateBytes []byte, certSANs []string) (bool, error) {
|
||||
crt, err := ParseCertificateBytes(certificateBytes)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ips := sets.New[string]()
|
||||
for _, ip := range crt.IPAddresses {
|
||||
ips.Insert(ip.String())
|
||||
}
|
||||
|
||||
dns := sets.New[string](crt.DNSNames...)
|
||||
|
||||
for _, e := range certSANs {
|
||||
if ip := net.ParseIP(e); ip != nil {
|
||||
if !ips.Has(ip.String()) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if !dns.Has(e) {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// CheckCertificateAndPrivateKeyPairValidity checks if the certificate and private key pair are valid.
|
||||
func CheckCertificateAndPrivateKeyPairValidity(certificate []byte, privateKey []byte) (bool, error) {
|
||||
switch {
|
||||
|
||||
@@ -62,7 +62,7 @@ func (e *EtcdClient) GrantPrivileges(ctx context.Context, user, dbName string) e
|
||||
permission := etcdclient.PermissionType(authpb.READWRITE)
|
||||
key := e.buildKey(dbName)
|
||||
|
||||
if _, err := e.Client.RoleGrantPermission(ctx, user, key, etcdclient.GetPrefixRangeEnd(key), permission); err != nil {
|
||||
if _, err := e.Client.RoleGrantPermission(ctx, dbName, key, etcdclient.GetPrefixRangeEnd(key), permission); err != nil {
|
||||
return errors.NewGrantPrivilegesError(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ import (
|
||||
|
||||
// CheckExists ensures that the default Datastore exists before starting the manager.
|
||||
func CheckExists(ctx context.Context, scheme *runtime.Scheme, datastoreName string) error {
|
||||
if datastoreName == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctrlClient, err := client.New(ctrl.GetConfigOrDie(), client.Options{Scheme: scheme})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create controlerruntime.Client: %w", err)
|
||||
|
||||
@@ -84,6 +84,14 @@ func (r *APIServerCertificate) UpdateTenantControlPlaneStatus(_ context.Context,
|
||||
func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {
|
||||
return func() error {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
// The Kubeadm configuration must be retrieved in advance:
|
||||
// this is required to check also the certificate SAN
|
||||
config, kadmErr := getStoredKubeadmConfiguration(ctx, r.Client, r.TmpDirectory, tenantControlPlane)
|
||||
if kadmErr != nil {
|
||||
logger.Error(kadmErr, "cannot retrieve stored kubeadm configuration", "err", kadmErr.Error())
|
||||
|
||||
return fmt.Errorf("failed to generate certificate and private key: %w", kadmErr)
|
||||
}
|
||||
// Retrieving the TenantControlPlane CA:
|
||||
// this is required to trigger a new generation in case of Certificate Authority rotation.
|
||||
namespacedName := k8stypes.NamespacedName{Namespace: tenantControlPlane.GetNamespace(), Name: tenantControlPlane.Status.Certificates.CA.SecretName}
|
||||
@@ -121,18 +129,16 @@ func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *k
|
||||
logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", kubeadmconstants.APIServerCertAndKeyBaseName, err.Error()))
|
||||
}
|
||||
|
||||
if isCAValid && isCertValid {
|
||||
dnsNamesMatches, dnsErr := crypto.CheckCertificateSAN(r.resource.Data[kubeadmconstants.APIServerCertName], config.InitConfiguration.APIServer.CertSANs)
|
||||
if dnsErr != nil {
|
||||
logger.Info(fmt.Sprintf("%s SAN check returned an error: %s", kubeadmconstants.APIServerCertAndKeyBaseName, err.Error()))
|
||||
}
|
||||
|
||||
if isCAValid && isCertValid && dnsNamesMatches {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
config, err := getStoredKubeadmConfiguration(ctx, r.Client, r.TmpDirectory, tenantControlPlane)
|
||||
if err != nil {
|
||||
logger.Error(err, "cannot generate certificate and private key in api server certificate", "details", err.Error())
|
||||
|
||||
return fmt.Errorf("failed to generate certificate and private key: %w", err)
|
||||
}
|
||||
|
||||
ca := kubeadm.CertificatePrivateKeyPair{
|
||||
Name: kubeadmconstants.CACertAndKeyBaseName,
|
||||
Certificate: secretCA.Data[kubeadmconstants.CACertName],
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/util/retry"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
@@ -47,7 +48,7 @@ func (r *Config) CleanUp(context.Context, *kamajiv1alpha1.TenantControlPlane) (b
|
||||
func (r *Config) Define(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
|
||||
r.resource = &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: r.getPrefixedName(tenantControlPlane),
|
||||
Name: utilities.AddTenantPrefix(r.GetName(), tenantControlPlane),
|
||||
Namespace: tenantControlPlane.GetNamespace(),
|
||||
},
|
||||
}
|
||||
@@ -55,10 +56,6 @@ func (r *Config) Define(_ context.Context, tenantControlPlane *kamajiv1alpha1.Te
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Config) getPrefixedName(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) string {
|
||||
return utilities.AddTenantPrefix(r.GetName(), tenantControlPlane)
|
||||
}
|
||||
|
||||
func (r *Config) GetClient() client.Client {
|
||||
return r.Client
|
||||
}
|
||||
@@ -67,28 +64,32 @@ func (r *Config) CreateOrUpdate(ctx context.Context, tenantControlPlane *kamajiv
|
||||
return utilities.CreateOrUpdateWithConflict(ctx, r.Client, r.resource, r.mutate(ctx, tenantControlPlane))
|
||||
}
|
||||
|
||||
// Delete doesn't perform any deletion process: the Secret object has owner relationship
|
||||
// with the TenantControlPlane object, which has been previously deleted.
|
||||
func (r *Config) Delete(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlane) error {
|
||||
secret := r.resource.DeepCopy()
|
||||
|
||||
if err := r.Client.Get(ctx, types.NamespacedName{Name: r.resource.Name, Namespace: r.resource.Namespace}, secret); err != nil {
|
||||
if kubeerrors.IsNotFound(err) {
|
||||
return nil
|
||||
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
if err := r.Client.Get(ctx, types.NamespacedName{Name: r.resource.Name, Namespace: r.resource.Namespace}, secret); err != nil {
|
||||
if kubeerrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "cannot retrieve the DataStore Secret for removal")
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "cannot retrieve the DataStore Secret for removal")
|
||||
}
|
||||
secret.SetFinalizers(nil)
|
||||
|
||||
secret.SetFinalizers(nil)
|
||||
if err := r.Client.Update(ctx, secret); err != nil {
|
||||
if kubeerrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := r.Client.Update(ctx, secret); err != nil {
|
||||
if kubeerrors.IsNotFound(err) {
|
||||
return nil
|
||||
return errors.Wrap(err, "cannot remove DataStore Secret finalizers")
|
||||
}
|
||||
|
||||
return errors.Wrap(err, "cannot remove DataStore Secret finalizers")
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Config) GetName() string {
|
||||
|
||||
@@ -28,7 +28,7 @@ var _ = Describe("DatastoreStorageConfig", func() {
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
ctx = context.Background()
|
||||
ctx = context.Background() //nolint:fatcontext
|
||||
|
||||
tcp = &kamajiv1alpha1.TenantControlPlane{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/utils/ptr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
@@ -103,6 +104,13 @@ func (r *KubernetesServiceResource) mutate(ctx context.Context, tenantControlPla
|
||||
case kamajiv1alpha1.ServiceTypeLoadBalancer:
|
||||
r.resource.Spec.Type = corev1.ServiceTypeLoadBalancer
|
||||
|
||||
if tenantControlPlane.Spec.NetworkProfile.LoadBalancerClass != nil {
|
||||
r.resource.Spec.LoadBalancerClass = ptr.To(*tenantControlPlane.Spec.NetworkProfile.LoadBalancerClass)
|
||||
}
|
||||
|
||||
if len(tenantControlPlane.Spec.NetworkProfile.LoadBalancerSourceRanges) > 0 {
|
||||
r.resource.Spec.LoadBalancerSourceRanges = tenantControlPlane.Spec.NetworkProfile.LoadBalancerSourceRanges
|
||||
}
|
||||
if len(address) > 0 {
|
||||
r.resource.Spec.LoadBalancerIP = address
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (r *ServiceResource) ShouldStatusBeUpdated(_ context.Context, tenantControl
|
||||
return true
|
||||
}
|
||||
|
||||
for i := 0; i < len(resourceIngresses); i++ {
|
||||
for i := range resourceIngresses {
|
||||
if resourceIngresses[i].Hostname != statusIngresses[i].Hostname ||
|
||||
resourceIngresses[i].IP != statusIngresses[i].IP ||
|
||||
len(resourceIngresses[i].Ports) != len(statusIngresses[i].Ports) {
|
||||
@@ -55,7 +55,7 @@ func (r *ServiceResource) ShouldStatusBeUpdated(_ context.Context, tenantControl
|
||||
|
||||
resourcePorts := resourceIngresses[i].Ports
|
||||
statusPorts := statusIngresses[i].Ports
|
||||
for j := 0; j < len(resourcePorts); j++ {
|
||||
for j := range resourcePorts {
|
||||
if resourcePorts[j].Port != statusPorts[j].Port ||
|
||||
resourcePorts[j].Protocol != statusPorts[j].Protocol {
|
||||
return true
|
||||
|
||||
@@ -229,7 +229,7 @@ func (r *KubeadmPhase) UpdateTenantControlPlaneStatus(ctx context.Context, tenan
|
||||
func (r *KubeadmPhase) GetStatus(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (kamajiv1alpha1.KubeadmConfigChecksumDependant, error) {
|
||||
switch r.Phase {
|
||||
case PhaseUploadConfigKubeadm, PhaseUploadConfigKubelet, PhaseClusterAdminRBAC:
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil
|
||||
case PhaseBootstrapToken:
|
||||
return &tenantControlPlane.Status.KubeadmPhase.BootstrapToken, nil
|
||||
default:
|
||||
|
||||
@@ -21,19 +21,19 @@ const (
|
||||
)
|
||||
|
||||
type Resource interface {
|
||||
Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error
|
||||
ShouldCleanup(*kamajiv1alpha1.TenantControlPlane) bool
|
||||
CleanUp(context.Context, *kamajiv1alpha1.TenantControlPlane) (bool, error)
|
||||
CreateOrUpdate(context.Context, *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error)
|
||||
Define(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) error
|
||||
ShouldCleanup(tcp *kamajiv1alpha1.TenantControlPlane) bool
|
||||
CleanUp(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (bool, error)
|
||||
CreateOrUpdate(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error)
|
||||
GetName() string
|
||||
ShouldStatusBeUpdated(context.Context, *kamajiv1alpha1.TenantControlPlane) bool
|
||||
UpdateTenantControlPlaneStatus(context.Context, *kamajiv1alpha1.TenantControlPlane) error
|
||||
ShouldStatusBeUpdated(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) bool
|
||||
UpdateTenantControlPlaneStatus(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) error
|
||||
}
|
||||
|
||||
type DeletableResource interface {
|
||||
GetName() string
|
||||
Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error
|
||||
Delete(context.Context, *kamajiv1alpha1.TenantControlPlane) error
|
||||
Define(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) error
|
||||
Delete(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) error
|
||||
}
|
||||
|
||||
type KubeadmResource interface {
|
||||
@@ -45,9 +45,9 @@ type KubeadmPhaseResource interface {
|
||||
Resource
|
||||
KubeadmResource
|
||||
GetClient() client.Client
|
||||
GetKubeadmFunction(context.Context, *kamajiv1alpha1.TenantControlPlane) (func(clientset.Interface, *kubeadm.Configuration) ([]byte, error), error)
|
||||
GetStatus(*kamajiv1alpha1.TenantControlPlane) (kamajiv1alpha1.KubeadmConfigChecksumDependant, error)
|
||||
SetKubeadmConfigChecksum(string)
|
||||
GetKubeadmFunction(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (func(clientset.Interface, *kubeadm.Configuration) ([]byte, error), error)
|
||||
GetStatus(tcp *kamajiv1alpha1.TenantControlPlane) (kamajiv1alpha1.KubeadmConfigChecksumDependant, error)
|
||||
SetKubeadmConfigChecksum(checksum string)
|
||||
GetWatchedObject() client.Object
|
||||
GetPredicateFunc() func(obj client.Object) bool
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
package upgrade
|
||||
|
||||
const (
|
||||
KubeadmVersion = "v1.31.1"
|
||||
KubeadmVersion = "v1.31.4"
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@ func (d DataStoreSecretValidation) OnDelete(runtime.Object) AdmissionResponse {
|
||||
}
|
||||
|
||||
func (d DataStoreSecretValidation) OnUpdate(object runtime.Object, _ runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(ctx context.Context, _ admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
secret := object.(*corev1.Secret) //nolint:forcetypeassert
|
||||
|
||||
dsList := &kamajiv1alpha1.DataStoreList{}
|
||||
|
||||
@@ -25,7 +25,7 @@ type DataStoreValidation struct {
|
||||
}
|
||||
|
||||
func (d DataStoreValidation) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(ctx context.Context, _ admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
ds := object.(*kamajiv1alpha1.DataStore) //nolint:forcetypeassert
|
||||
|
||||
return nil, d.validate(ctx, *ds)
|
||||
@@ -33,7 +33,7 @@ func (d DataStoreValidation) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
}
|
||||
|
||||
func (d DataStoreValidation) OnDelete(object runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(ctx context.Context, _ admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
ds := object.(*kamajiv1alpha1.DataStore) //nolint:forcetypeassert
|
||||
|
||||
tcpList := &kamajiv1alpha1.TenantControlPlaneList{}
|
||||
@@ -50,7 +50,7 @@ func (d DataStoreValidation) OnDelete(object runtime.Object) AdmissionResponse {
|
||||
}
|
||||
|
||||
func (d DataStoreValidation) OnUpdate(object runtime.Object, oldObj runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(ctx context.Context, _ admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
newDs, oldDs := object.(*kamajiv1alpha1.DataStore), oldObj.(*kamajiv1alpha1.DataStore) //nolint:forcetypeassert
|
||||
|
||||
if oldDs.Spec.Driver != newDs.Spec.Driver {
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
type AdmissionResponse func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error)
|
||||
|
||||
type Handler interface {
|
||||
OnCreate(runtime.Object) AdmissionResponse
|
||||
OnDelete(runtime.Object) AdmissionResponse
|
||||
OnCreate(obj runtime.Object) AdmissionResponse
|
||||
OnDelete(obj runtime.Object) AdmissionResponse
|
||||
OnUpdate(newObject runtime.Object, prevObject runtime.Object) AdmissionResponse
|
||||
}
|
||||
|
||||
@@ -23,10 +23,14 @@ type TenantControlPlaneDataStore struct {
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneDataStore) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(ctx context.Context, _ admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
return nil, t.check(ctx, tcp.Spec.DataStore)
|
||||
if tcp.Spec.DataStore != "" {
|
||||
return nil, t.check(ctx, tcp.Spec.DataStore)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +39,14 @@ func (t TenantControlPlaneDataStore) OnDelete(runtime.Object) AdmissionResponse
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneDataStore) OnUpdate(object runtime.Object, _ runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(ctx context.Context, _ admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
return nil, t.check(ctx, tcp.Spec.DataStore)
|
||||
if tcp.Spec.DataStore != "" {
|
||||
return nil, t.check(ctx, tcp.Spec.DataStore)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package handlers
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -23,12 +24,27 @@ type TenantControlPlaneDefaults struct {
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneDefaults) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
original := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
defaulted := original.DeepCopy()
|
||||
t.defaultUnsetFields(defaulted)
|
||||
|
||||
if len(defaulted.Spec.NetworkProfile.DNSServiceIPs) == 0 {
|
||||
ip, _, err := net.ParseCIDR(defaulted.Spec.NetworkProfile.ServiceCIDR)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot define resulting DNS Service IP")
|
||||
}
|
||||
switch {
|
||||
case ip.To4() != nil:
|
||||
ip[len(ip)-1] += 10
|
||||
case ip.To16() != nil:
|
||||
ip[len(ip)-1] += 16
|
||||
}
|
||||
|
||||
defaulted.Spec.NetworkProfile.DNSServiceIPs = []string{ip.String()}
|
||||
}
|
||||
|
||||
operations, err := utils.JSONPatch(original, defaulted)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot create patch responses upon Tenant Control Plane creation")
|
||||
@@ -48,7 +64,7 @@ func (t TenantControlPlaneDefaults) OnUpdate(runtime.Object, runtime.Object) Adm
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneDefaults) defaultUnsetFields(tcp *kamajiv1alpha1.TenantControlPlane) {
|
||||
if len(tcp.Spec.DataStore) == 0 {
|
||||
if len(tcp.Spec.DataStore) == 0 && t.DefaultDatastore != "" {
|
||||
tcp.Spec.DataStore = t.DefaultDatastore
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ var _ = Describe("TCP Defaulting Webhook", func() {
|
||||
},
|
||||
Spec: kamajiv1alpha1.TenantControlPlaneSpec{},
|
||||
}
|
||||
ctx = context.Background()
|
||||
ctx = context.Background() //nolint:fatcontext
|
||||
})
|
||||
|
||||
Describe("fields missing", func() {
|
||||
|
||||
@@ -54,7 +54,7 @@ func (t TenantControlPlaneDeployment) shouldTriggerCheck(newTCP, oldTCP kamajiv1
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneDeployment) OnUpdate(newObject runtime.Object, oldObject runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(ctx context.Context, _ admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp, previousTCP := newObject.(*kamajiv1alpha1.TenantControlPlane), oldObject.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
if !t.shouldTriggerCheck(*tcp, *previousTCP) {
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
type TenantControlPlaneKubeletAddresses struct{}
|
||||
|
||||
func (t TenantControlPlaneKubeletAddresses) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
return nil, t.validatePreferredKubeletAddressTypes(tcp.Spec.Kubernetes.Kubelet.PreferredAddressTypes)
|
||||
@@ -31,7 +31,7 @@ func (t TenantControlPlaneKubeletAddresses) OnDelete(runtime.Object) AdmissionRe
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneKubeletAddresses) OnUpdate(object runtime.Object, _ runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
return nil, t.validatePreferredKubeletAddressTypes(tcp.Spec.Kubernetes.Kubelet.PreferredAddressTypes)
|
||||
|
||||
58
internal/webhook/handlers/tcp_lb_src_ranges.go
Normal file
58
internal/webhook/handlers/tcp_lb_src_ranges.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/webhook/utils"
|
||||
)
|
||||
|
||||
type TenantControlPlaneLoadBalancerSourceRanges struct{}
|
||||
|
||||
func (t TenantControlPlaneLoadBalancerSourceRanges) handle(tcp *kamajiv1alpha1.TenantControlPlane) error {
|
||||
for _, sourceCIDR := range tcp.Spec.NetworkProfile.LoadBalancerSourceRanges {
|
||||
_, _, err := net.ParseCIDR(sourceCIDR)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid LoadBalancer source CIDR %s, %s", sourceCIDR, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneLoadBalancerSourceRanges) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
if err := t.handle(tcp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneLoadBalancerSourceRanges) OnDelete(runtime.Object) AdmissionResponse {
|
||||
return utils.NilOp()
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneLoadBalancerSourceRanges) OnUpdate(object runtime.Object, _ runtime.Object) AdmissionResponse {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
if err := t.handle(tcp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
64
internal/webhook/handlers/tcp_lb_src_ranges_test.go
Normal file
64
internal/webhook/handlers/tcp_lb_src_ranges_test.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package handlers_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/webhook/handlers"
|
||||
)
|
||||
|
||||
var _ = Describe("TCP LoadBalancer Source Ranges Webhook", func() {
|
||||
var (
|
||||
ctx context.Context
|
||||
t handlers.TenantControlPlaneLoadBalancerSourceRanges
|
||||
tcp *kamajiv1alpha1.TenantControlPlane
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
t = handlers.TenantControlPlaneLoadBalancerSourceRanges{}
|
||||
tcp = &kamajiv1alpha1.TenantControlPlane{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "tcp",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: kamajiv1alpha1.TenantControlPlaneSpec{},
|
||||
}
|
||||
ctx = context.Background() //nolint:fatcontext
|
||||
})
|
||||
|
||||
It("allows creation when valid CIDR ranges are provided", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = kamajiv1alpha1.ServiceTypeLoadBalancer
|
||||
tcp.Spec.NetworkProfile.LoadBalancerSourceRanges = []string{"192.168.0.0/24"}
|
||||
_, err := t.OnCreate(tcp)(ctx, admission.Request{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("allows creation when LoadBalancer service has no CIDR field", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = kamajiv1alpha1.ServiceTypeLoadBalancer
|
||||
_, err := t.OnCreate(tcp)(ctx, admission.Request{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("allows creation when LoadBalancer service has an empty CIDR list", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = kamajiv1alpha1.ServiceTypeLoadBalancer
|
||||
tcp.Spec.NetworkProfile.LoadBalancerSourceRanges = []string{}
|
||||
_, err := t.OnCreate(tcp)(ctx, admission.Request{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("denies creation when source ranges contain invalid CIDRs", func() {
|
||||
tcp.Spec.ControlPlane.Service.ServiceType = kamajiv1alpha1.ServiceTypeLoadBalancer
|
||||
tcp.Spec.NetworkProfile.LoadBalancerSourceRanges = []string{"192.168.0.0/33"}
|
||||
_, err := t.OnCreate(tcp)(ctx, admission.Request{})
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("invalid LoadBalancer source CIDR 192.168.0.0/33"))
|
||||
})
|
||||
})
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
type TenantControlPlaneName struct{}
|
||||
|
||||
func (t TenantControlPlaneName) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
if errs := validation.IsDNS1035Label(tcp.Name); len(errs) > 0 {
|
||||
|
||||
@@ -59,7 +59,7 @@ func (t TenantControlPlaneServiceCIDR) OnDelete(runtime.Object) AdmissionRespons
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneServiceCIDR) OnUpdate(object runtime.Object, _ runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
if err := t.handle(tcp); err != nil {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
type TenantControlPlaneVersion struct{}
|
||||
|
||||
func (t TenantControlPlaneVersion) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
ver, err := semver.New(t.normalizeKubernetesVersion(tcp.Spec.Kubernetes.Version))
|
||||
@@ -56,7 +56,7 @@ func (t TenantControlPlaneVersion) OnDelete(runtime.Object) AdmissionResponse {
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneVersion) OnUpdate(object runtime.Object, oldObject runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
newTCP, oldTCP := object.(*kamajiv1alpha1.TenantControlPlane), oldObject.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
oldVer, oldErr := semver.Make(t.normalizeKubernetesVersion(oldTCP.Spec.Kubernetes.Version))
|
||||
|
||||
Reference in New Issue
Block a user