mirror of
https://github.com/clastix/kamaji.git
synced 2026-02-28 16:50:29 +00:00
Compare commits
43 Commits
edge-25.4.
...
edge-25.7.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cac1631523 | ||
|
|
d1eb860918 | ||
|
|
6c76bd6a97 | ||
|
|
462d52332c | ||
|
|
63a29b4b59 | ||
|
|
e366dc3959 | ||
|
|
0ab8843418 | ||
|
|
ce5fe906aa | ||
|
|
09c9743465 | ||
|
|
8290e84c3f | ||
|
|
678aca6229 | ||
|
|
d6a94dfa5e | ||
|
|
3fd1882e43 | ||
|
|
d40996daa9 | ||
|
|
b5956e43a5 | ||
|
|
c97767b54f | ||
|
|
464984f091 | ||
|
|
d7b21b5814 | ||
|
|
3230a70475 | ||
|
|
b0c9034994 | ||
|
|
22f9c36b15 | ||
|
|
d5d0295736 | ||
|
|
80afd43c9f | ||
|
|
32ef65820d | ||
|
|
eeb12c232b | ||
|
|
ce8d5f2516 | ||
|
|
1ac72ff22f | ||
|
|
501bd7a7ca | ||
|
|
ba3249f220 | ||
|
|
c156322fe3 | ||
|
|
ca622ef9ae | ||
|
|
a9c324e2e5 | ||
|
|
95a32ee5d4 | ||
|
|
9874700b28 | ||
|
|
994162c5b0 | ||
|
|
8ba99bd6c6 | ||
|
|
16438ebed8 | ||
|
|
f750073af6 | ||
|
|
6b10c89d2f | ||
|
|
8bd1f53568 | ||
|
|
9db4ccc5f1 | ||
|
|
fd49c238f5 | ||
|
|
b53adbfd6e |
3
.github/workflows/e2e.yaml
vendored
3
.github/workflows/e2e.yaml
vendored
@@ -33,7 +33,7 @@ on:
|
||||
jobs:
|
||||
kind:
|
||||
name: Kubernetes
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -46,5 +46,6 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y golang-cfssl
|
||||
sudo swapoff -a
|
||||
sudo modprobe br_netfilter
|
||||
- name: e2e testing
|
||||
run: make e2e
|
||||
|
||||
6
.github/workflows/helm.yaml
vendored
6
.github/workflows/helm.yaml
vendored
@@ -2,8 +2,7 @@ name: Helm Chart
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "*" ]
|
||||
tags: [ "helm-v*" ]
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "*" ]
|
||||
|
||||
@@ -32,7 +31,8 @@ jobs:
|
||||
- name: Linting Chart
|
||||
run: helm lint ./charts/kamaji
|
||||
release:
|
||||
if: startsWith(github.ref, 'refs/tags/helm-v')
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
needs: [ "lint", "diff" ]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
23
.github/workflows/pr.yaml
vendored
Normal file
23
.github/workflows/pr.yaml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
name: Check PR Title
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, reopened, synchronize]
|
||||
|
||||
jobs:
|
||||
semantic-pr-title:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5
|
||||
with:
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
chore
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -9,6 +9,7 @@ Feel free to open a Pull-Request to get yours listed.
|
||||
|:-|:-|:-|:-|:-|
|
||||
| Vendor | Aknostic | 2023 | [link](https://aknostic.com) | Aknostic is a cloud-native consultancy company using Kamaji to build a Kubernetes based PaaS. |
|
||||
| R&D | Aruba | 2024 | [link](https://www.aruba.it/home.aspx) | Aruba Cloud is an Italian Cloud Service Provider evaluating Kamaji to build and offer [Managed Kubernetes Service](https://my.arubacloud.com). |
|
||||
| Vendor | CBWS | 2025 | [link](https://cbws.nl) | CBWS is an European Cloud Provider using Kamaji to build and offer their [Managed Kubernetes Service](https://cbws.nl/cloud/kubernetes/). |
|
||||
| Vendor | DCloud | 2024 | [link](https://dcloud.co.id) | DCloud is an Indonesian Cloud Provider using Kamaji to build and offer [Managed Kubernetes Service](https://dcloud.co.id/dkubes.html). |
|
||||
| Vendor | Dinova | 2025 | [link](https://dinova.one/) | Dinova is an Italian cloud services provider that integrates Kamaji in its datacenters to offer fully managed Kubernetes clusters. |
|
||||
| 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). |
|
||||
|
||||
29
Makefile
29
Makefile
@@ -73,47 +73,47 @@ help: ## Display this help.
|
||||
.PHONY: ko
|
||||
ko: $(KO) ## Download ko locally if necessary.
|
||||
$(KO): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/ko || GOBIN=$(LOCALBIN) go install github.com/google/ko@v0.14.1
|
||||
test -s $(LOCALBIN)/ko || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" github.com/google/ko@v0.14.1
|
||||
|
||||
.PHONY: yq
|
||||
yq: $(YQ) ## Download yq locally if necessary.
|
||||
$(YQ): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/yq || GOBIN=$(LOCALBIN) go install github.com/mikefarah/yq/v4@v4.44.2
|
||||
test -s $(LOCALBIN)/yq || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" github.com/mikefarah/yq/v4@v4.44.2
|
||||
|
||||
.PHONY: helm
|
||||
helm: $(HELM) ## Download helm locally if necessary.
|
||||
$(HELM): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/helm || GOBIN=$(LOCALBIN) go install helm.sh/helm/v3/cmd/helm@v3.9.0
|
||||
test -s $(LOCALBIN)/helm || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" helm.sh/helm/v3/cmd/helm@v3.9.0
|
||||
|
||||
.PHONY: ginkgo
|
||||
ginkgo: $(GINKGO) ## Download ginkgo locally if necessary.
|
||||
$(GINKGO): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/ginkgo || GOBIN=$(LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo
|
||||
test -s $(LOCALBIN)/ginkgo || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" github.com/onsi/ginkgo/v2/ginkgo
|
||||
|
||||
.PHONY: kind
|
||||
kind: $(KIND) ## Download kind locally if necessary.
|
||||
$(KIND): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/kind || GOBIN=$(LOCALBIN) go install sigs.k8s.io/kind/cmd/kind@v0.14.0
|
||||
test -s $(LOCALBIN)/kind || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" sigs.k8s.io/kind/cmd/kind@v0.14.0
|
||||
|
||||
.PHONY: controller-gen
|
||||
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
|
||||
$(CONTROLLER_GEN): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.1
|
||||
test -s $(LOCALBIN)/controller-gen || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.1
|
||||
|
||||
.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/v2/cmd/golangci-lint@v2.0.2
|
||||
test -s $(LOCALBIN)/golangci-lint || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.0.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
|
||||
test -s $(LOCALBIN)/crdoc || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" 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)
|
||||
test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) CGO_ENABLED=0 go install -ldflags="-s -w" sigs.k8s.io/controller-runtime/tools/setup-envtest@$(ENVTEST_VERSION)
|
||||
|
||||
##@ Development
|
||||
|
||||
@@ -250,6 +250,15 @@ e2e: env build load helm ginkgo cert-manager ## Create a KinD cluster, install K
|
||||
|
||||
##@ Document
|
||||
|
||||
CAPI_URL = https://github.com/clastix/cluster-api-control-plane-provider-kamaji.git
|
||||
CAPI_DIR := $(shell mktemp -d)
|
||||
CRDS_DIR := $(shell mktemp -d)
|
||||
|
||||
.PHONY: apidoc
|
||||
apidoc: apidocs-gen
|
||||
$(APIDOCS_GEN) crdoc --resources charts/kamaji/crds --output docs/content/reference/api.md --template docs/templates/reference-cr.tmpl
|
||||
@cp charts/kamaji/crds/*.yaml $(CRDS_DIR)
|
||||
@git clone $(CAPI_URL) $(CAPI_DIR)
|
||||
@cp $(CAPI_DIR)/config/crd/bases/*.yaml $(CRDS_DIR)
|
||||
@rm -rf $(CAPI_DIR)
|
||||
$(APIDOCS_GEN) crdoc --resources $(CRDS_DIR) --output docs/content/reference/api.md --template docs/templates/reference-cr.tmpl
|
||||
@rm -rf $(CRDS_DIR)
|
||||
|
||||
10
api/v1alpha1/tenantcontrolplane_const.go
Normal file
10
api/v1alpha1/tenantcontrolplane_const.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package v1alpha1
|
||||
|
||||
const (
|
||||
// PausedReconciliationAnnotation is an annotation that can be applied to
|
||||
// Tenant Control Plane objects to prevent the controller from processing such a resource.
|
||||
PausedReconciliationAnnotation = "kamaji.clastix.io/paused"
|
||||
)
|
||||
@@ -122,6 +122,12 @@ type ExternalKubernetesObjectStatus struct {
|
||||
LastUpdate metav1.Time `json:"lastUpdate,omitempty"`
|
||||
}
|
||||
|
||||
type KonnectivityAgentStatus struct {
|
||||
ExternalKubernetesObjectStatus `json:",inline"`
|
||||
|
||||
Mode KonnectivityAgentMode `json:"mode,omitempty"`
|
||||
}
|
||||
|
||||
// KonnectivityStatus defines the status of Konnectivity as Addon.
|
||||
type KonnectivityStatus struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
@@ -130,7 +136,7 @@ type KonnectivityStatus struct {
|
||||
Kubeconfig KubeconfigStatus `json:"kubeconfig,omitempty"`
|
||||
ServiceAccount ExternalKubernetesObjectStatus `json:"sa,omitempty"`
|
||||
ClusterRoleBinding ExternalKubernetesObjectStatus `json:"clusterrolebinding,omitempty"`
|
||||
Agent ExternalKubernetesObjectStatus `json:"agent,omitempty"`
|
||||
Agent KonnectivityAgentStatus `json:"agent,omitempty"`
|
||||
Service KubernetesServiceStatus `json:"service,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -67,11 +67,12 @@ const (
|
||||
|
||||
type KubeletSpec struct {
|
||||
// Ordered list of the preferred NodeAddressTypes to use for kubelet connections.
|
||||
// Default to Hostname, InternalIP, ExternalIP.
|
||||
//+kubebuilder:default={"Hostname","InternalIP","ExternalIP"}
|
||||
// Default to InternalIP, ExternalIP, Hostname.
|
||||
//+kubebuilder:default={"InternalIP","ExternalIP","Hostname"}
|
||||
//+kubebuilder:validation:MinItems=1
|
||||
//+listType=set
|
||||
PreferredAddressTypes []KubeletPreferredAddressType `json:"preferredAddressTypes,omitempty"`
|
||||
// CGroupFS defines the cgroup driver for Kubelet
|
||||
// CGroupFS defines the cgroup driver for Kubelet
|
||||
// https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/
|
||||
CGroupFS CGroupDriver `json:"cgroupfs,omitempty"`
|
||||
}
|
||||
@@ -235,6 +236,15 @@ type KonnectivityServerSpec struct {
|
||||
ExtraArgs ExtraArgs `json:"extraArgs,omitempty"`
|
||||
}
|
||||
|
||||
type KonnectivityAgentMode string
|
||||
|
||||
var (
|
||||
KonnectivityAgentModeDaemonSet KonnectivityAgentMode = "DaemonSet"
|
||||
KonnectivityAgentModeDeployment KonnectivityAgentMode = "Deployment"
|
||||
)
|
||||
|
||||
//+kubebuilder:validation:XValidation:rule="!(self.mode == 'DaemonSet' && has(self.replicas) && self.replicas != 0) && !(self.mode == 'Deployment' && self.replicas == 0)",message="replicas must be 0 when mode is DaemonSet, and greater than 0 when mode is Deployment"
|
||||
|
||||
type KonnectivityAgentSpec struct {
|
||||
// AgentImage defines the container image for Konnectivity's agent.
|
||||
//+kubebuilder:default=registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
@@ -247,13 +257,21 @@ type KonnectivityAgentSpec struct {
|
||||
//+kubebuilder:default={{key: "CriticalAddonsOnly", operator: "Exists"}}
|
||||
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
||||
ExtraArgs ExtraArgs `json:"extraArgs,omitempty"`
|
||||
// Mode allows specifying the Agent deployment mode: Deployment, or DaemonSet (default).
|
||||
//+kubebuilder:default="DaemonSet"
|
||||
//+kubebuilder:validation:Enum=DaemonSet;Deployment
|
||||
Mode KonnectivityAgentMode `json:"mode,omitempty"`
|
||||
// Replicas defines the number of replicas when Mode is Deployment.
|
||||
// Must be 0 if Mode is DaemonSet.
|
||||
//+kubebuilder:validation:Optional
|
||||
Replicas int32 `json:"replicas,omitempty"`
|
||||
}
|
||||
|
||||
// KonnectivitySpec defines the spec for Konnectivity.
|
||||
type KonnectivitySpec struct {
|
||||
//+kubebuilder:default={version:"v0.28.6",image:"registry.k8s.io/kas-network-proxy/proxy-server",port:8132}
|
||||
KonnectivityServerSpec KonnectivityServerSpec `json:"server,omitempty"`
|
||||
//+kubebuilder:default={version:"v0.28.6",image:"registry.k8s.io/kas-network-proxy/proxy-agent"}
|
||||
//+kubebuilder:default={version:"v0.28.6",image:"registry.k8s.io/kas-network-proxy/proxy-agent",mode:"DaemonSet"}
|
||||
KonnectivityAgentSpec KonnectivityAgentSpec `json:"agent,omitempty"`
|
||||
}
|
||||
|
||||
@@ -304,6 +322,7 @@ type TenantControlPlaneSpec struct {
|
||||
//+kubebuilder:subresource:scale:specpath=.spec.controlPlane.deployment.replicas,statuspath=.status.kubernetesResources.deployment.replicas,selectorpath=.status.kubernetesResources.deployment.selector
|
||||
//+kubebuilder:resource:categories=kamaji,shortName=tcp
|
||||
//+kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.kubernetes.version",description="Kubernetes version"
|
||||
//+kubebuilder:printcolumn:name="Installed Version",type="string",JSONPath=".status.kubernetesResources.version.version",description="The actual installed Kubernetes version from status"
|
||||
//+kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.kubernetesResources.version.status",description="Status"
|
||||
//+kubebuilder:printcolumn:name="Control-Plane endpoint",type="string",JSONPath=".status.controlPlaneEndpoint",description="Tenant Control Plane Endpoint (API server)"
|
||||
//+kubebuilder:printcolumn:name="Kubeconfig",type="string",JSONPath=".status.kubeconfig.admin.secretName",description="Secret which contains admin kubeconfig"
|
||||
|
||||
@@ -808,6 +808,22 @@ func (in *KonnectivityAgentSpec) DeepCopy() *KonnectivityAgentSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KonnectivityAgentStatus) DeepCopyInto(out *KonnectivityAgentStatus) {
|
||||
*out = *in
|
||||
in.ExternalKubernetesObjectStatus.DeepCopyInto(&out.ExternalKubernetesObjectStatus)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KonnectivityAgentStatus.
|
||||
func (in *KonnectivityAgentStatus) DeepCopy() *KonnectivityAgentStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(KonnectivityAgentStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KonnectivityConfigMap) DeepCopyInto(out *KonnectivityConfigMap) {
|
||||
*out = *in
|
||||
|
||||
@@ -21,3 +21,8 @@
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
# Helm source files
|
||||
README.md.gotmpl
|
||||
.helmignore
|
||||
# Build tools
|
||||
Makefile
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
- name: kamaji-etcd
|
||||
repository: https://clastix.github.io/charts
|
||||
version: 0.9.2
|
||||
digest: sha256:ba76d3a30e5e20dbbbbcc36a0e7465d4b1adacc956061e7f6ea47b99fc8f08a6
|
||||
generated: "2025-03-14T21:23:30.421915+09:00"
|
||||
version: 0.11.0
|
||||
digest: sha256:96b4115b8c02f771f809ec1bed3be3a3903e7e8315d6966aa54b0f73230ea421
|
||||
generated: "2025-07-03T09:19:19.835421461+02:00"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: v0.0.0
|
||||
appVersion: latest
|
||||
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: 0.0.0
|
||||
version: 0.0.0+latest
|
||||
dependencies:
|
||||
- name: kamaji-etcd
|
||||
repository: https://clastix.github.io/charts
|
||||
version: ">=0.9.2"
|
||||
version: ">=0.11.0"
|
||||
condition: kamaji-etcd.deploy
|
||||
annotations:
|
||||
catalog.cattle.io/certified: partner
|
||||
@@ -46,4 +46,5 @@ annotations:
|
||||
artifacthub.io/operator: "true"
|
||||
artifacthub.io/operatorCapabilities: "full lifecycle"
|
||||
artifacthub.io/changes: |
|
||||
- Using dependency chart `kamaji-etcd` as a default DataStore.
|
||||
- kind: added
|
||||
description: Releasing latest chart at every push
|
||||
|
||||
@@ -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.9.2 |
|
||||
| https://clastix.github.io/charts | kamaji-etcd | >=0.11.0 |
|
||||
|
||||
[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`.
|
||||
@@ -82,10 +82,7 @@ Here the values you can override:
|
||||
| image.repository | string | `"clastix/kamaji"` | The container image of the Kamaji controller. |
|
||||
| image.tag | string | `nil` | Overrides the image tag whose default is the chart appVersion. |
|
||||
| imagePullSecrets | list | `[]` | |
|
||||
| kamaji-etcd.datastore.enabled | bool | `true` | |
|
||||
| kamaji-etcd.datastore.name | string | `"default"` | |
|
||||
| kamaji-etcd.deploy | bool | `true` | |
|
||||
| kamaji-etcd.fullnameOverride | string | `"kamaji-etcd"` | |
|
||||
| kamaji-etcd | object | `{"clusterDomain":"cluster.local","datastore":{"enabled":true,"name":"default"},"deploy":true,"fullnameOverride":"kamaji-etcd"}` | Subchart: See https://github.com/clastix/kamaji-etcd/blob/master/charts/kamaji-etcd/values.yaml |
|
||||
| livenessProbe | object | `{"httpGet":{"path":"/healthz","port":"healthcheck"},"initialDelaySeconds":15,"periodSeconds":20}` | The livenessProbe for the controller container |
|
||||
| loggingDevel.enable | bool | `false` | Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false) |
|
||||
| metricsBindAddress | string | `":8080"` | The address the metric endpoint binds to. (default ":8080") |
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Kamaji
|
||||
|
||||
Kamaji deploys and operates Kubernetes at scale with a fraction of the operational burden.
|
||||
|
||||
Useful links:
|
||||
- [Kamaji Github repository](https://github.com/clastix/kamaji)
|
||||
- [Kamaji Documentation](https://kamaji.clastix.io)
|
||||
|
||||
## Requirements
|
||||
|
||||
* Kubernetes v1.22+
|
||||
* Helm v3
|
||||
@@ -23,6 +23,10 @@ spec:
|
||||
jsonPath: .spec.kubernetes.version
|
||||
name: Version
|
||||
type: string
|
||||
- description: The actual installed Kubernetes version from status
|
||||
jsonPath: .status.kubernetesResources.version.version
|
||||
name: Installed Version
|
||||
type: string
|
||||
- description: Status
|
||||
jsonPath: .status.kubernetesResources.version.status
|
||||
name: Status
|
||||
@@ -92,6 +96,7 @@ spec:
|
||||
agent:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
mode: DaemonSet
|
||||
version: v0.28.6
|
||||
properties:
|
||||
extraArgs:
|
||||
@@ -107,6 +112,19 @@ spec:
|
||||
default: registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
description: AgentImage defines the container image for Konnectivity's agent.
|
||||
type: string
|
||||
mode:
|
||||
default: DaemonSet
|
||||
description: 'Mode allows specifying the Agent deployment mode: Deployment, or DaemonSet (default).'
|
||||
enum:
|
||||
- DaemonSet
|
||||
- Deployment
|
||||
type: string
|
||||
replicas:
|
||||
description: |-
|
||||
Replicas defines the number of replicas when Mode is Deployment.
|
||||
Must be 0 if Mode is DaemonSet.
|
||||
format: int32
|
||||
type: integer
|
||||
tolerations:
|
||||
default:
|
||||
- key: CriticalAddonsOnly
|
||||
@@ -156,6 +174,9 @@ spec:
|
||||
description: Version for Konnectivity agent.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-validations:
|
||||
- message: replicas must be 0 when mode is DaemonSet, and greater than 0 when mode is Deployment
|
||||
rule: '!(self.mode == ''DaemonSet'' && has(self.replicas) && self.replicas != 0) && !(self.mode == ''Deployment'' && self.replicas == 0)'
|
||||
server:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-server
|
||||
@@ -6535,7 +6556,7 @@ spec:
|
||||
properties:
|
||||
cgroupfs:
|
||||
description: |-
|
||||
CGroupFS defines the cgroup driver for Kubelet
|
||||
CGroupFS defines the cgroup driver for Kubelet
|
||||
https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/
|
||||
enum:
|
||||
- systemd
|
||||
@@ -6543,12 +6564,12 @@ spec:
|
||||
type: string
|
||||
preferredAddressTypes:
|
||||
default:
|
||||
- Hostname
|
||||
- InternalIP
|
||||
- ExternalIP
|
||||
- Hostname
|
||||
description: |-
|
||||
Ordered list of the preferred NodeAddressTypes to use for kubelet connections.
|
||||
Default to Hostname, InternalIP, ExternalIP.
|
||||
Default to InternalIP, ExternalIP, Hostname.
|
||||
items:
|
||||
enum:
|
||||
- Hostname
|
||||
@@ -6559,6 +6580,7 @@ spec:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
x-kubernetes-list-type: set
|
||||
type: object
|
||||
version:
|
||||
description: Kubernetes Version for the tenant control plane
|
||||
@@ -6680,6 +6702,8 @@ spec:
|
||||
description: Last time when k8s object was updated
|
||||
format: date-time
|
||||
type: string
|
||||
mode:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
namespace:
|
||||
|
||||
@@ -98,9 +98,12 @@ loggingDevel:
|
||||
# -- If specified, all the Kamaji instances with an unassigned DataStore will inherit this default value.
|
||||
defaultDatastoreName: default
|
||||
|
||||
# -- Subchart: See https://github.com/clastix/kamaji-etcd/blob/master/charts/kamaji-etcd/values.yaml
|
||||
kamaji-etcd:
|
||||
deploy: true
|
||||
fullnameOverride: kamaji-etcd
|
||||
## -- Important, this must match your management cluster's clusterDomain, otherwise the init jobs will fail
|
||||
clusterDomain: "cluster.local"
|
||||
datastore:
|
||||
enabled: true
|
||||
name: default
|
||||
@@ -108,4 +111,4 @@ kamaji-etcd:
|
||||
# -- Disable the analytics traces collection
|
||||
telemetry:
|
||||
disabled: false
|
||||
|
||||
|
||||
|
||||
@@ -223,7 +223,6 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
handlers.TenantControlPlaneCertSANs{},
|
||||
handlers.TenantControlPlaneName{},
|
||||
handlers.TenantControlPlaneVersion{},
|
||||
handlers.TenantControlPlaneKubeletAddresses{},
|
||||
handlers.TenantControlPlaneDataStore{Client: mgr.GetClient()},
|
||||
handlers.TenantControlPlaneDeployment{
|
||||
Client: mgr.GetClient(),
|
||||
@@ -307,7 +306,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
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", "", "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().StringVar(&migrateJobImage, "migrate-image", fmt.Sprintf("%s/clastix/kamaji:%s", internal.ContainerRepository, 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.")
|
||||
cmd.Flags().StringVar(&managerServiceName, "webhook-service-name", "kamaji-webhook-service", "The Kamaji webhook server Service name which is used to get validation webhooks, required for the TenantControlPlane migration jobs.")
|
||||
|
||||
@@ -22,9 +22,10 @@ import (
|
||||
func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
// CLI flags
|
||||
var (
|
||||
tenantControlPlane string
|
||||
targetDataStore string
|
||||
timeout time.Duration
|
||||
tenantControlPlane string
|
||||
targetDataStore string
|
||||
cleanupPriorMigration bool
|
||||
timeout time.Duration
|
||||
)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
@@ -95,6 +96,20 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
defer targetConnection.Close()
|
||||
|
||||
if cleanupPriorMigration {
|
||||
log.Info("Checking if target DataStore should be clean-up prior migration")
|
||||
|
||||
if exists, _ := targetConnection.DBExists(ctx, tcp.Status.Storage.Setup.Schema); exists {
|
||||
log.Info("A colliding schema on target DataStore is present, cleaning up")
|
||||
|
||||
if dErr := targetConnection.DeleteDB(ctx, tcp.Status.Storage.Setup.Schema); dErr != nil {
|
||||
return fmt.Errorf("error cleaning up prior migration: %s", dErr.Error())
|
||||
}
|
||||
|
||||
log.Info("Cleaning up prior migration has been completed")
|
||||
}
|
||||
}
|
||||
// Start migrating from the old Datastore to the new one
|
||||
log.Info("migration from origin to target started")
|
||||
|
||||
@@ -110,6 +125,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
|
||||
cmd.Flags().StringVar(&tenantControlPlane, "tenant-control-plane", "", "Namespaced-name of the TenantControlPlane that must be migrated (e.g.: default/test)")
|
||||
cmd.Flags().StringVar(&targetDataStore, "target-datastore", "", "Name of the Datastore to which the TenantControlPlane will be migrated")
|
||||
cmd.Flags().BoolVar(&cleanupPriorMigration, "cleanup-prior-migration", false, "When set to true, migration job will drop existing data in the target DataStore: useful to avoid stale data when migrating back and forth between DataStores.")
|
||||
cmd.Flags().DurationVar(&timeout, "timeout", 5*time.Minute, "Amount of time for the context timeout")
|
||||
|
||||
_ = cmd.MarkFlagRequired("tenant-control-plane")
|
||||
|
||||
@@ -22,3 +22,5 @@ spec:
|
||||
konnectivity:
|
||||
server:
|
||||
port: 8132
|
||||
agent:
|
||||
mode: DaemonSet
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/controllers/utils"
|
||||
"github.com/clastix/kamaji/internal/constants"
|
||||
"github.com/clastix/kamaji/internal/crypto"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
@@ -41,19 +42,25 @@ func (s *CertificateLifecycle) Reconcile(ctx context.Context, request reconcile.
|
||||
|
||||
logger.Info("starting CertificateLifecycle handling")
|
||||
|
||||
secret := corev1.Secret{}
|
||||
err := s.client.Get(ctx, request.NamespacedName, &secret)
|
||||
if k8serrors.IsNotFound(err) {
|
||||
logger.Info("resource have been deleted, skipping")
|
||||
var secret corev1.Secret
|
||||
if err := s.client.Get(ctx, request.NamespacedName, &secret); err != nil {
|
||||
if k8serrors.IsNotFound(err) {
|
||||
logger.Info("resource may have been deleted, skipping")
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
logger.Error(err, "cannot retrieve the required resource")
|
||||
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if utils.IsPaused(&secret) {
|
||||
logger.Info("paused reconciliation, no further actions")
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
checkType, ok := secret.GetLabels()[constants.ControllerLabelResource]
|
||||
if !ok {
|
||||
logger.Info("missing controller label, shouldn't happen")
|
||||
@@ -62,14 +69,15 @@ func (s *CertificateLifecycle) Reconcile(ctx context.Context, request reconcile.
|
||||
}
|
||||
|
||||
var crt *x509.Certificate
|
||||
var err error
|
||||
|
||||
switch checkType {
|
||||
case "x509":
|
||||
case utilities.CertificateX509Label:
|
||||
crt, err = s.extractCertificateFromBareSecret(secret)
|
||||
case "kubeconfig":
|
||||
case utilities.CertificateKubeconfigLabel:
|
||||
crt, err = s.extractCertificateFromKubeconfig(secret)
|
||||
default:
|
||||
err = fmt.Errorf("unsupported strategy, %s", checkType)
|
||||
return reconcile.Result{}, fmt.Errorf("unsupported strategy, %q", checkType)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -99,7 +107,7 @@ func (s *CertificateLifecycle) Reconcile(ctx context.Context, request reconcile.
|
||||
|
||||
logger.Info("certificate is still valid, enqueuing back", "after", after.String())
|
||||
|
||||
return reconcile.Result{Requeue: true, RequeueAfter: after}, nil
|
||||
return reconcile.Result{RequeueAfter: after}, nil
|
||||
}
|
||||
|
||||
func (s *CertificateLifecycle) extractCertificateFromBareSecret(secret corev1.Secret) (*x509.Certificate, error) {
|
||||
@@ -144,7 +152,7 @@ func (s *CertificateLifecycle) extractCertificateFromKubeconfig(secret corev1.Se
|
||||
func (s *CertificateLifecycle) SetupWithManager(mgr controllerruntime.Manager) error {
|
||||
s.client = mgr.GetClient()
|
||||
|
||||
supportedStrategies := sets.New[string]("x509", "kubeconfig")
|
||||
supportedStrategies := sets.New[string](utilities.CertificateX509Label, utilities.CertificateKubeconfigLabel)
|
||||
|
||||
return controllerruntime.NewControllerManagedBy(mgr).
|
||||
For(&corev1.Secret{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
|
||||
|
||||
@@ -43,7 +43,7 @@ func (r *DataStore) Reconcile(ctx context.Context, request reconcile.Request) (r
|
||||
var ds kamajiv1alpha1.DataStore
|
||||
if err := r.Client.Get(ctx, request.NamespacedName, &ds); err != nil {
|
||||
if k8serrors.IsNotFound(err) {
|
||||
logger.Info("resource have been deleted, skipping")
|
||||
logger.Info("resource may have been deleted, skipping")
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
@@ -53,6 +53,12 @@ func (r *DataStore) Reconcile(ctx context.Context, request reconcile.Request) (r
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if utils.IsPaused(&ds) {
|
||||
logger.Info("paused reconciliation, no further actions")
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
var tcpList kamajiv1alpha1.TenantControlPlaneList
|
||||
|
||||
updateErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
@@ -23,6 +24,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
sooterrors "github.com/clastix/kamaji/controllers/soot/controllers/errors"
|
||||
"github.com/clastix/kamaji/controllers/utils"
|
||||
"github.com/clastix/kamaji/internal/kubeadm"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
@@ -39,7 +41,11 @@ type CoreDNS struct {
|
||||
func (c *CoreDNS) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) {
|
||||
tcp, err := c.GetTenantControlPlaneFunc()
|
||||
if err != nil {
|
||||
c.Logger.Error(err, "cannot retrieve TenantControlPlane")
|
||||
if errors.Is(err, sooterrors.ErrPausedReconciliation) {
|
||||
c.Logger.Info(err.Error())
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
10
controllers/soot/controllers/errors/paused_reconciliation.go
Normal file
10
controllers/soot/controllers/errors/paused_reconciliation.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var ErrPausedReconciliation = errors.New("paused reconciliation, no further actions")
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/rbac/v1"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
"github.com/clastix/kamaji/controllers"
|
||||
sooterrors "github.com/clastix/kamaji/controllers/soot/controllers/errors"
|
||||
"github.com/clastix/kamaji/controllers/utils"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/resources/konnectivity"
|
||||
@@ -40,6 +42,12 @@ type KonnectivityAgent struct {
|
||||
func (k *KonnectivityAgent) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) {
|
||||
tcp, err := k.GetTenantControlPlaneFunc()
|
||||
if err != nil {
|
||||
if errors.Is(err, sooterrors.ErrPausedReconciliation) {
|
||||
k.Logger.Info(err.Error())
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
k.Logger.Error(err, "cannot retrieve TenantControlPlane")
|
||||
|
||||
return reconcile.Result{}, err
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/utils/ptr"
|
||||
controllerruntime "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
sooterrors "github.com/clastix/kamaji/controllers/soot/controllers/errors"
|
||||
"github.com/clastix/kamaji/controllers/utils"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
)
|
||||
@@ -34,6 +36,12 @@ type KubeadmPhase struct {
|
||||
func (k *KubeadmPhase) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) {
|
||||
tcp, err := k.GetTenantControlPlaneFunc()
|
||||
if err != nil {
|
||||
if errors.Is(err, sooterrors.ErrPausedReconciliation) {
|
||||
k.logger.Info(err.Error())
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
@@ -23,6 +24,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
sooterrors "github.com/clastix/kamaji/controllers/soot/controllers/errors"
|
||||
"github.com/clastix/kamaji/controllers/utils"
|
||||
"github.com/clastix/kamaji/internal/kubeadm"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
@@ -39,6 +41,12 @@ type KubeProxy struct {
|
||||
func (k *KubeProxy) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) {
|
||||
tcp, err := k.GetTenantControlPlaneFunc()
|
||||
if err != nil {
|
||||
if errors.Is(err, sooterrors.ErrPausedReconciliation) {
|
||||
k.Logger.Info(err.Error())
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
k.Logger.Error(err, "cannot retrieve TenantControlPlane")
|
||||
|
||||
return reconcile.Result{}, err
|
||||
|
||||
@@ -6,10 +6,12 @@ package controllers
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
pointer "k8s.io/utils/ptr"
|
||||
controllerruntime "sigs.k8s.io/controller-runtime"
|
||||
@@ -24,6 +26,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
"github.com/clastix/kamaji/api/v1alpha1"
|
||||
sooterrors "github.com/clastix/kamaji/controllers/soot/controllers/errors"
|
||||
"github.com/clastix/kamaji/controllers/utils"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
@@ -41,11 +44,17 @@ type Migrate struct {
|
||||
func (m *Migrate) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile.Result, error) {
|
||||
tcp, err := m.GetTenantControlPlaneFunc()
|
||||
if err != nil {
|
||||
if errors.Is(err, sooterrors.ErrPausedReconciliation) {
|
||||
m.Logger.Info(err.Error())
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
// Cannot detect the status of the TenantControlPlane, enqueuing back
|
||||
if tcp.Status.Kubernetes.Version.Status == nil {
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
return reconcile.Result{RequeueAfter: time.Second}, nil
|
||||
}
|
||||
|
||||
switch *tcp.Status.Kubernetes.Version.Status {
|
||||
@@ -66,7 +75,7 @@ func (m *Migrate) Reconcile(ctx context.Context, _ reconcile.Request) (reconcile
|
||||
|
||||
func (m *Migrate) cleanup(ctx context.Context) error {
|
||||
if err := m.Client.Delete(ctx, m.object()); err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/controllers/finalizers"
|
||||
"github.com/clastix/kamaji/controllers/soot/controllers"
|
||||
"github.com/clastix/kamaji/controllers/soot/controllers/errors"
|
||||
"github.com/clastix/kamaji/controllers/utils"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
@@ -69,6 +70,10 @@ func (m *Manager) retrieveTenantControlPlane(ctx context.Context, request reconc
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if utils.IsPaused(tcp) {
|
||||
return nil, errors.ErrPausedReconciliation
|
||||
}
|
||||
|
||||
return tcp, nil
|
||||
}
|
||||
}
|
||||
@@ -213,7 +218,7 @@ func (m *Manager) Reconcile(ctx context.Context, request reconcile.Request) (res
|
||||
return nil
|
||||
})
|
||||
|
||||
return reconcile.Result{Requeue: true}, finalizerErr
|
||||
return reconcile.Result{RequeueAfter: time.Second}, finalizerErr
|
||||
}
|
||||
// Generating the manager and starting it:
|
||||
// in case of any error, reconciling the request to start it back from the beginning.
|
||||
@@ -377,7 +382,7 @@ func (m *Manager) Reconcile(ctx context.Context, request reconcile.Request) (res
|
||||
completedCh: completedCh,
|
||||
}
|
||||
|
||||
return reconcile.Result{Requeue: true}, nil
|
||||
return reconcile.Result{RequeueAfter: time.Second}, nil
|
||||
}
|
||||
|
||||
func (m *Manager) SetupWithManager(mgr manager.Manager) error {
|
||||
|
||||
@@ -85,7 +85,7 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
|
||||
tenantControlPlane, err := r.getTenantControlPlane(ctx, req.NamespacedName)()
|
||||
if k8serrors.IsNotFound(err) {
|
||||
log.Info("resource have been deleted, skipping")
|
||||
log.Info("resource may have been deleted, skipping")
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
@@ -95,17 +95,23 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if utils.IsPaused(tenantControlPlane) {
|
||||
log.Info("paused reconciliation, no further actions")
|
||||
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
releaser, err := mutex.Acquire(r.mutexSpec(tenantControlPlane))
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.As(err, &mutex.ErrTimeout):
|
||||
log.Info("acquire timed out, current process is blocked by another reconciliation")
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||
case errors.As(err, &mutex.ErrCancelled):
|
||||
log.Info("acquire cancelled")
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||
default:
|
||||
log.Error(err, "acquire failed")
|
||||
|
||||
@@ -125,7 +131,7 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
if errors.Is(err, ErrMissingDataStore) {
|
||||
log.Info(err.Error())
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||
}
|
||||
|
||||
log.Error(err, "cannot retrieve the DataStore for the given instance")
|
||||
@@ -186,7 +192,7 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
if kamajierrors.ShouldReconcileErrorBeIgnored(err) {
|
||||
log.V(1).Info("sentinel error, enqueuing back request", "error", err.Error())
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||
}
|
||||
|
||||
log.Error(err, "handling of resource failed", "resource", resource.GetName())
|
||||
@@ -202,7 +208,7 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
if kamajierrors.ShouldReconcileErrorBeIgnored(err) {
|
||||
log.V(1).Info("sentinel error, enqueuing back request", "error", err.Error())
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||
}
|
||||
|
||||
log.Error(err, "update of the resource failed", "resource", resource.GetName())
|
||||
@@ -215,7 +221,7 @@ func (r *TenantControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
|
||||
if result == resources.OperationResultEnqueueBack {
|
||||
log.Info("requested enqueuing back", "resources", resource.GetName())
|
||||
|
||||
return ctrl.Result{Requeue: true}, nil
|
||||
return ctrl.Result{RequeueAfter: time.Second}, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
19
controllers/utils/is_paused.go
Normal file
19
controllers/utils/is_paused.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
func IsPaused(obj client.Object) bool {
|
||||
if obj.GetAnnotations() == nil {
|
||||
return false
|
||||
}
|
||||
_, paused := obj.GetAnnotations()[v1alpha1.PausedReconciliationAnnotation]
|
||||
|
||||
return paused
|
||||
}
|
||||
@@ -1,22 +1,32 @@
|
||||
# Konnectivity
|
||||
|
||||
In traditional Kubernetes deployments, the control plane components need to communicate directly with worker nodes for various operations like executing commands in pods, retrieving logs, or managing port forwards. However, in many real-world environments, especially those spanning multiple networks or cloud providers, direct communication isn't always possible or desirable. This is where Konnectivity comes in.
|
||||
In traditional Kubernetes deployments, the control plane components need to communicate directly with worker nodes for various operations
|
||||
like executing commands in pods, retrieving logs, or managing port forwards.
|
||||
However, in many real-world environments, especially those spanning multiple networks or cloud providers,
|
||||
direct communication isn't always possible or desirable. This is where Konnectivity comes in.
|
||||
|
||||
## Understanding Konnectivity in Kamaji
|
||||
|
||||
Kamaji integrates [Konnectivity](https://kubernetes.io/docs/concepts/architecture/control-plane-node-communication/) as a core component of its architecture. Each Tenant Control Plane pod includes a konnectivity-server running as a sidecar container, which establishes and maintains secure tunnels with agents running on the worker nodes. This design ensures reliable communication even in complex network environments.
|
||||
Kamaji integrates [Konnectivity](https://kubernetes.io/docs/concepts/architecture/control-plane-node-communication/) as a core component of its architecture.
|
||||
Each Tenant Control Plane pod includes a konnectivity-server running as a sidecar container,
|
||||
which establishes and maintains secure tunnels with agents running on the worker nodes.
|
||||
|
||||
This design ensures reliable communication even in complex network environments.
|
||||
|
||||
The Konnectivity service consists of two main components:
|
||||
|
||||
1. **Konnectivity Server:**
|
||||
Runs alongside the control plane components in each Tenant Control Plane pod and is exposed on port 8132. It manages connections from worker nodes and routes traffic appropriately.
|
||||
Runs alongside the control plane components in each Tenant Control Plane pod and is exposed on port 8132.
|
||||
It manages connections from worker nodes and routes traffic appropriately.
|
||||
|
||||
2. **Konnectivity Agent:**
|
||||
Runs on each worker node and initiates outbound connections to its control plane's Konnectivity server. These connections are maintained to create a reliable tunnel for all control plane to worker node communication.
|
||||
Runs on worker nodes as _DaemonSet_ or _Deployment_ and initiates outbound connections to its control plane's Konnectivity server.
|
||||
These connections are maintained to create a reliable tunnel for all control plane to worker node communications.
|
||||
|
||||
## How It Works
|
||||
|
||||
When a worker node joins a Tenant Cluster, the Konnectivity agents automatically establish connections to their designated Konnectivity server. These connections are maintained continuously, ensuring reliable communication paths between the control plane and worker nodes.
|
||||
When a worker node joins a Tenant Cluster, the Konnectivity agents automatically establish connections to their designated Konnectivity server.
|
||||
These connections are maintained continuously, ensuring reliable communication paths between the control plane and worker nodes.
|
||||
|
||||
All traffic from the control plane to worker nodes flows through these established tunnels, enabling operations such as:
|
||||
|
||||
@@ -28,10 +38,51 @@ All traffic from the control plane to worker nodes flows through these establish
|
||||
|
||||
## Configuration and Management
|
||||
|
||||
Konnectivity is enabled by default in Kamaji, as it's considered a best practice for modern Kubernetes deployments. However, it can be disabled if your environment has different requirements or if you need to use alternative networking solutions.
|
||||
Konnectivity is enabled by default in Kamaji, as it's considered a best practice for modern Kubernetes deployments.
|
||||
However, it can be disabled if your environment has different requirements, or if you need to use alternative networking solutions.
|
||||
|
||||
The service is automatically configured when worker nodes join a cluster, without requiring any operational overhead. The connection details are managed as part of the standard node bootstrap process, making it transparent to cluster operators and users.
|
||||
The service is automatically configured when worker nodes join a cluster, without requiring any operational overhead.
|
||||
The connection details are managed as part of the standard node bootstrap process,
|
||||
making it transparent to cluster operators and users.
|
||||
|
||||
## Agent delivery mode
|
||||
|
||||
You can customise the Konnectivity Agent delivery mode via the Tenant Control Plane definition
|
||||
using the field `tenantcontrolplane.spec.addons.konnectivity.agent.mode`.
|
||||
|
||||
```yaml
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: TenantControlPlane
|
||||
metadata:
|
||||
name: konnectivity-example
|
||||
spec:
|
||||
controlPlane:
|
||||
deployment:
|
||||
replicas: 2
|
||||
service:
|
||||
serviceType: LoadBalancer
|
||||
kubernetes:
|
||||
version: "v1.33.0"
|
||||
networkProfile:
|
||||
port: 6443
|
||||
addons:
|
||||
konnectivity:
|
||||
server:
|
||||
port: 8132
|
||||
agent:
|
||||
## DaemonSet, Deployment
|
||||
mode: DaemonSet
|
||||
## When mode is Deployment, specify the desired Agent replicas
|
||||
# replicas: 2
|
||||
```
|
||||
|
||||
Available strategies are the following:
|
||||
- `DaemonSet`: runs on every node
|
||||
- `Deployment`: useful to decrease the resource footprint in certain workloads cluster,
|
||||
it allows customising also the amount of deployed replicas via the field
|
||||
`tenantcontrolplane.spec.addons.konnectivity.agent.replicas`.
|
||||
|
||||
---
|
||||
|
||||
By integrating Konnectivity as a core feature, Kamaji ensures that your Tenant Clusters can operate reliably and securely across any network topology, making it easier to build and manage distributed Kubernetes environments at scale.
|
||||
By integrating Konnectivity as a core feature, Kamaji ensures that your Tenant Clusters can operate reliably and securely across any network topology,
|
||||
making it easier to build and manage distributed Kubernetes environments at scale.
|
||||
|
||||
@@ -163,7 +163,7 @@ Installing Kamaji via Helm charts is the preferred way. Run the following comman
|
||||
```bash
|
||||
helm repo add clastix https://clastix.github.io/charts
|
||||
helm repo update
|
||||
helm install kamaji clastix/kamaji -n kamaji-system --create-namespace
|
||||
helm install kamaji clastix/kamaji -n kamaji-system --create-namespace --version 0.0.0+latest
|
||||
```
|
||||
|
||||
## Create Tenant Cluster
|
||||
|
||||
@@ -44,7 +44,7 @@ Any regular and conformant Kubernetes v1.22+ cluster can be turned into a Kamaji
|
||||
|
||||
- CNI module installed, eg. [Calico](https://github.com/projectcalico/calico), [Cilium](https://github.com/cilium/cilium).
|
||||
- CSI module installed with a Storage Class for the Tenant datastores. The [Local Path Provisioner](https://github.com/rancher/local-path-provisioner) is a suggested choice, even for production environments.
|
||||
- Support for LoadBalancer service type, eg. [MetalLB](https://metallb.universe.tf/), or cloud based.
|
||||
- Support for LoadBalancer service type, eg. [MetalLB](https://metallb.io/), or cloud based.
|
||||
- Optionally, a Monitoring Stack installed, eg. [Prometheus](https://github.com/prometheus-community).
|
||||
|
||||
Make sure you have a `kubeconfig` file with admin permissions on the cluster you want to turn into Kamaji Management Cluster and check you can access:
|
||||
@@ -69,17 +69,20 @@ helm install \
|
||||
|
||||
## Install Kamaji Controller
|
||||
|
||||
Installing Kamaji via Helm charts is the preferred way to deploy the Kamaji controller. The Helm chart is available in the `charts` directory of the Kamaji repository.
|
||||
Installing Kamaji via Helm charts is the preferred way to deploy the Kamaji controller.
|
||||
The Helm chart is available in the `charts` directory of the Kamaji repository, or as Helm Chart versioned as `0.0.0+latest`
|
||||
|
||||
!!! info "Stable Releases"
|
||||
As of July 2024 [Clastix Labs](https://github.com/clastix) no longer publish stable release artifacts. Stable releases are offered on a subscription basis by [CLASTIX](https://clastix.io), the main Kamaji project contributor.
|
||||
As of July 2024 [Clastix Labs](https://github.com/clastix) no longer publish version pinned release artifacts.
|
||||
Version pinned and stable releases are offered on a subscription basis by [CLASTIX](https://clastix.io), the main Kamaji project contributor.
|
||||
|
||||
Run the following commands to install the latest edge release of Kamaji:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/clastix/kamaji
|
||||
cd kamaji
|
||||
helm install kamaji charts/kamaji -n kamaji-system --create-namespace \
|
||||
helm install kamaji clastix/kamaji \
|
||||
--version 0.0.0+latest \
|
||||
--namespace kamaji-system \
|
||||
--create-namespace \
|
||||
--set image.tag=latest
|
||||
```
|
||||
|
||||
@@ -195,7 +198,7 @@ When a Tenant Control Plane is created, Kamaji waits for the LoadBalancer to pro
|
||||
|
||||
If you need to use a specific address for your Tenant Control Plane, you can specify it by setting the `tcp.spec.networkProfile.address` field in the Tenant Control Plane manifest. This optional field ensures that Kamaji uses your preferred address. However, if the specified address is unavailable, the Tenant Control Plane will remain in a `NotReady` state until the address becomes available.
|
||||
|
||||
To ensure that the LoadBalancer controller uses your specified address for the Service, you'll need to use controller-specific annotations. For instance, if you're using MetalLB as your LoadBalancer controller, you can add the `metallb.universe.tf/loadBalancerIPs` annotation to your Service definition, allowing the LoadBalancer controller to select the specified address:
|
||||
To ensure that the LoadBalancer controller uses your specified address for the Service, you'll need to use controller-specific annotations. For instance, if you're using MetalLB as your LoadBalancer controller, you can add the `metallb.io/loadBalancerIPs` annotation to your Service definition, allowing the LoadBalancer controller to select the specified address:
|
||||
|
||||
```yaml
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
@@ -212,7 +215,7 @@ spec:
|
||||
serviceType: LoadBalancer
|
||||
additionalMetadata:
|
||||
annotations:
|
||||
metallb.universe.tf/loadBalancerIPs: 172.18.255.104 # use this address
|
||||
metallb.io/loadBalancerIPs: 172.18.255.104 # use this address
|
||||
kubernetes:
|
||||
version: "v1.30.0"
|
||||
kubelet:
|
||||
|
||||
@@ -91,22 +91,20 @@ EOF
|
||||
```
|
||||
|
||||
## Installing Kamaji
|
||||
|
||||
- Clone the Kamaji repository
|
||||
- Add the Clastix Repo to the Helm Manager.
|
||||
|
||||
```
|
||||
git clone https://github.com/clastix/kamaji
|
||||
cd kamaji
|
||||
helm repo add clastix https://clastix.github.io/charts
|
||||
```
|
||||
|
||||
- Install Kamaji with Helm
|
||||
|
||||
```
|
||||
helm upgrade --install kamaji charts/kamaji \
|
||||
helm upgrade --install kamaji clastix/kamaji \
|
||||
--namespace kamaji-system \
|
||||
--create-namespace \
|
||||
--set image.tag=latest \
|
||||
--set 'resources=null'
|
||||
--set 'resources=null' \
|
||||
--version 0.0.0+latest
|
||||
```
|
||||
|
||||
- Watch the progress of the deployments
|
||||
@@ -146,6 +144,12 @@ SECRET=""
|
||||
kubectl get secret $SECRET -o jsonpath='{.data.admin\.conf}'|base64 -d > /tmp/kamaji.conf
|
||||
```
|
||||
|
||||
- (options) if you run kind in some specific systems with `docker bridge network`, eg macOS, you may need to access the `kind` container, and perform the `kubectl` actions:
|
||||
|
||||
```
|
||||
docker exec -it $(docker container list | grep kamaji-control-plane | awk '{print $1}') bash
|
||||
```
|
||||
|
||||
- Export the `kubeconfig` file to the environment variable `KUBECONFIG`
|
||||
|
||||
```
|
||||
@@ -159,4 +163,4 @@ kubectl version
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
A Video Tutorial of the [demonstration](https://www.youtube.com/watch?v=hDTvnOyUmo4&t=577s) can also be viewed.
|
||||
A Video Tutorial of the [demonstration](https://www.youtube.com/watch?v=hDTvnOyUmo4&t=577s) can also be viewed.
|
||||
|
||||
@@ -19,50 +19,44 @@ All the certificates are created with the `kubeadm` defaults, thus their validit
|
||||
|
||||
## How to rotate certificates
|
||||
|
||||
If you need to manually rotate one of these certificates, the required operation is the deletion for the given Secret.
|
||||
All certificates can be rotated at the same time, or one by one: this is possible by annotating resources using
|
||||
the well-known annotation `certs.kamaji.clastix.io/rotate`.
|
||||
|
||||
```
|
||||
$: kubectl get secret
|
||||
NAME TYPE DATA AGE
|
||||
k8s-126-admin-kubeconfig Opaque 1 12m
|
||||
k8s-126-api-server-certificate Opaque 2 12m
|
||||
k8s-126-api-server-kubelet-client-certificate Opaque 2 3h45m
|
||||
k8s-126-ca Opaque 4 3h45m
|
||||
k8s-126-controller-manager-kubeconfig Opaque 1 3h45m
|
||||
k8s-126-datastore-certificate Opaque 3 3h45m
|
||||
k8s-126-datastore-config Opaque 4 3h45m
|
||||
k8s-126-front-proxy-ca-certificate Opaque 2 3h45m
|
||||
k8s-126-front-proxy-client-certificate Opaque 2 3h45m
|
||||
k8s-126-konnectivity-certificate kubernetes.io/tls 2 3h45m
|
||||
k8s-126-konnectivity-kubeconfig Opaque 1 3h45m
|
||||
k8s-126-sa-certificate Opaque 2 3h45m
|
||||
k8s-126-scheduler-kubeconfig Opaque 1 3h45m
|
||||
k8s-133-admin-kubeconfig Opaque 1 12m
|
||||
k8s-133-api-server-certificate Opaque 2 12m
|
||||
k8s-133-api-server-kubelet-client-certificate Opaque 2 3h45m
|
||||
k8s-133-ca Opaque 4 3h45m
|
||||
k8s-133-controller-manager-kubeconfig Opaque 1 3h45m
|
||||
k8s-133-datastore-certificate Opaque 3 3h45m
|
||||
k8s-133-datastore-config Opaque 4 3h45m
|
||||
k8s-133-front-proxy-ca-certificate Opaque 2 3h45m
|
||||
k8s-133-front-proxy-client-certificate Opaque 2 3h45m
|
||||
k8s-133-konnectivity-certificate kubernetes.io/tls 2 3h45m
|
||||
k8s-133-konnectivity-kubeconfig Opaque 1 3h45m
|
||||
k8s-133-sa-certificate Opaque 2 3h45m
|
||||
k8s-133-scheduler-kubeconfig Opaque 1 3h45m
|
||||
```
|
||||
|
||||
Once this operation is performed, Kamaji will be notified of the missing certificate, and it will create it back.
|
||||
Once this operation is performed, Kamaji will trigger a certificate renewal,
|
||||
reporting the rotation date time as the annotation `certs.kamaji.clastix.io/rotate` value.
|
||||
|
||||
```
|
||||
$: kubectl delete secret -l kamaji.clastix.io/certificate_lifecycle_controller=x509
|
||||
secret "k8s-126-api-server-certificate" deleted
|
||||
secret "k8s-126-api-server-kubelet-client-certificate" deleted
|
||||
secret "k8s-126-front-proxy-client-certificate" deleted
|
||||
secret "k8s-126-konnectivity-certificate" deleted
|
||||
$: kubectl annotate secret -l kamaji.clastix.io/certificate_lifecycle_controller=x509 certs.kamaji.clastix.io/rotate=""
|
||||
secret/k8s-133-api-server-certificate annotated
|
||||
secret/k8s-133-api-server-kubelet-client-certificate annotated
|
||||
secret/k8s-133-datastore-certificate annotated
|
||||
secret/k8s-133-front-proxy-client-certificate annotated
|
||||
secret/k8s-133-konnectivity-certificate annotated
|
||||
|
||||
$: kubectl delete secret -l kamaji.clastix.io/certificate_lifecycle_controller=x509
|
||||
NAME TYPE DATA AGE
|
||||
k8s-126-admin-kubeconfig Opaque 1 15m
|
||||
k8s-126-api-server-certificate Opaque 2 12s
|
||||
k8s-126-api-server-kubelet-client-certificate Opaque 2 12s
|
||||
k8s-126-ca Opaque 4 3h48m
|
||||
k8s-126-controller-manager-kubeconfig Opaque 1 3h48m
|
||||
k8s-126-datastore-certificate Opaque 3 3h48m
|
||||
k8s-126-datastore-config Opaque 4 3h48m
|
||||
k8s-126-front-proxy-ca-certificate Opaque 2 3h48m
|
||||
k8s-126-front-proxy-client-certificate Opaque 2 12s
|
||||
k8s-126-konnectivity-certificate kubernetes.io/tls 2 11s
|
||||
k8s-126-konnectivity-kubeconfig Opaque 1 3h48m
|
||||
k8s-126-sa-certificate Opaque 2 3h48m
|
||||
k8s-126-scheduler-kubeconfig Opaque 1 3h48m
|
||||
$: kubectl get secrets -l kamaji.clastix.io/certificate_lifecycle_controller=x509 -ojson | jq -r '.items[] | "\(.metadata.name) rotated at \(.metadata.annotations["certs.kamaji.clastix.io/rotate"])"'
|
||||
k8s-133-api-server-certificate rotated at 2025-07-15 15:15:08.842191367 +0200 CEST m=+325.785000014
|
||||
k8s-133-api-server-kubelet-client-certificate rotated at 2025-07-15 15:15:10.468139865 +0200 CEST m=+327.410948506
|
||||
k8s-133-datastore-certificate rotated at 2025-07-15 15:15:15.454468752 +0200 CEST m=+332.397277417
|
||||
k8s-133-front-proxy-client-certificate rotated at 2025-07-15 15:15:13.279920467 +0200 CEST m=+330.222729097
|
||||
k8s-133-konnectivity-certificate rotated at 2025-07-15 15:15:17.361431671 +0200 CEST m=+334.304240277
|
||||
```
|
||||
|
||||
You can notice the secrets have been automatically created back, as well as a TenantControlPlane rollout with the updated certificates.
|
||||
@@ -70,23 +64,24 @@ You can notice the secrets have been automatically created back, as well as a Te
|
||||
```
|
||||
$: kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
k8s-126-76768bdf89-82w8g 4/4 Running 0 58s
|
||||
k8s-126-76768bdf89-fwltl 4/4 Running 0 58s
|
||||
k8s-133-67bf496c8c-27bmp 4/4 Running 0 4m52s
|
||||
k8s-133-67bf496c8c-x4t76 4/4 Running 0 4m52s
|
||||
```
|
||||
|
||||
The same occurs with the `kubeconfig` ones.
|
||||
|
||||
```
|
||||
$: kubectl delete secret -l kamaji.clastix.io/certificate_lifecycle_controller=kubeconfig
|
||||
secret "k8s-126-admin-kubeconfig" deleted
|
||||
secret "k8s-126-controller-manager-kubeconfig" deleted
|
||||
secret "k8s-126-konnectivity-kubeconfig" deleted
|
||||
secret "k8s-126-scheduler-kubeconfig" deleted
|
||||
$: kubectl annotate secret -l kamaji.clastix.io/certificate_lifecycle_controller=kubeconfig certs.kamaji.clastix.io/rotate=""
|
||||
secret/k8s-133-admin-kubeconfig annotated
|
||||
secret/k8s-133-controller-manager-kubeconfig annotated
|
||||
secret/k8s-133-konnectivity-kubeconfig annotated
|
||||
secret/k8s-133-scheduler-kubeconfig annotated
|
||||
|
||||
$: kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
k8s-126-576c775b5d-2gr9h 4/4 Running 0 50s
|
||||
k8s-126-576c775b5d-jmvlm 4/4 Running 0 50s
|
||||
$: kubectl get secrets -l kamaji.clastix.io/certificate_lifecycle_controller=kubeconfig -ojson | jq -r '.items[] | "\(.metadata.name) rotated at \(.metadata.annotations["certs.kamaji.clastix.io/rotate"])"'
|
||||
k8s-133-admin-kubeconfig rotated at 2025-07-15 15:20:41.688181782 +0200 CEST m=+658.630990441
|
||||
k8s-133-controller-manager-kubeconfig rotated at 2025-07-15 15:20:42.712211056 +0200 CEST m=+659.655019677
|
||||
k8s-133-konnectivity-kubeconfig rotated at 2025-07-15 15:20:46.405567865 +0200 CEST m=+663.348376504
|
||||
k8s-133-scheduler-kubeconfig rotated at 2025-07-15 15:20:46.333718563 +0200 CEST m=+663.276527216
|
||||
```
|
||||
|
||||
## Automatic certificates rotation
|
||||
@@ -108,11 +103,11 @@ e.g.: set the value `7d` to trigger the renewal a week before the effective expi
|
||||
|
||||
Kamaji is also taking care of your Tenant Clusters Certificate Authority.
|
||||
|
||||
This can be rotated manually by deleting the following secret.
|
||||
This can be rotated manually like other certificates by using the annotation `certs.kamaji.clastix.io/rotate`
|
||||
|
||||
```
|
||||
$: kubectl delete secret k8s-126-ca
|
||||
secret "k8s-126-ca" deleted
|
||||
$: kubectl annotate secret k8s-133-ca certs.kamaji.clastix.io/rotate=""
|
||||
secret/k8s-133-ca annotated
|
||||
```
|
||||
|
||||
Once this occurs the TenantControlPlane will enter in the `CertificateAuthorityRotating` status.
|
||||
@@ -120,26 +115,26 @@ Once this occurs the TenantControlPlane will enter in the `CertificateAuthorityR
|
||||
```
|
||||
$: kubectl get tcp -w
|
||||
NAME VERSION STATUS CONTROL-PLANE ENDPOINT KUBECONFIG DATASTORE AGE
|
||||
k8s-126 v1.26.0 Ready 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 Ready 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 Ready 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 Ready 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 Ready 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-126 v1.26.0 Ready 172.18.255.200:6443 k8s-126-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 Ready 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 CertificateAuthorityRotating 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 Ready 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 Ready 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 Ready 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 Ready 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
k8s-133 v1.33.0 Ready 172.18.255.200:6443 k8s-133-admin-kubeconfig default 3h58m
|
||||
```
|
||||
|
||||
This operation is intended to be performed manually since a new Certificate Authority requires the restart of all the components, as well as of the nodes:
|
||||
in such case, you will need to distribute the new Certificate Authority and the new nodes certificates.
|
||||
This operation is intended to be performed manually since a new Certificate Authority requires the restart of all the components,
|
||||
as well as of the nodes: in such a case, you will need to distribute the new Certificate Authority and the new nodes certificates.
|
||||
|
||||
Given the sensibility of such operation, the `Secret` controller will not check the _CA_, which is offering validity of 10 years as `kubeadm` default values.
|
||||
|
||||
@@ -160,7 +160,6 @@ tenant-00 v1.25.2 Ready 192.168.32.200:6443 tenant-00-admin-kubec
|
||||
|
||||
During the datastore migration, the Tenant Control Plane is put in read-only mode to avoid misalignments between source and destination datastores. If tenant users try to update the data, an admission controller denies the request with the following message:
|
||||
|
||||
|
||||
```shell
|
||||
Error from server (the current Control Plane is in freezing mode due to a maintenance mode,
|
||||
all the changes are blocked: removing the webhook may lead to an inconsistent state upon its completion):
|
||||
@@ -169,9 +168,17 @@ admission webhook "catchall.migrate.kamaji.clastix.io" denied the request
|
||||
|
||||
After a while, depending on the amount of data to migrate, the Tenant Control Plane is put back in full operating mode by the Kamaji controller.
|
||||
|
||||
Migration is expected to complete in 5 minutes.
|
||||
However, that timeout can be customized at the `TenantControlPlane` level with the annotation `kamaji.clastix.io/migration-timeout` with a Go-duration value (e.g.: `5m`).
|
||||
|
||||
!!! info "Leftover"
|
||||
Please, note the datastore migration leaves the data on the default datastore, so you have to remove it manually.
|
||||
|
||||
!!! info "Avoiding stale DataStore content"
|
||||
When migrating `TenantControlPlane` across DataStore, a collision with the __schema__ name could happen,
|
||||
leading to unexpected results such as old data still available.
|
||||
The annotation `kamaji.clastix.io/cleanup-prior-migration=true` allows to enforce the clean-up of the target `DataStore` schema in case of collision.
|
||||
|
||||
## Post migration
|
||||
After migrating data to the new datastore, complete the migration procedure by restarting the `kubelet.service` on all the tenant worker nodes.
|
||||
|
||||
@@ -181,7 +188,7 @@ After migrating data to the new datastore, complete the migration procedure by r
|
||||
When migrating between datastores, the Kamaji controller automatically creates a migration job to transfer data from the source to the destination datastore. By default, this job uses the same image version as the running Kamaji controller. If you need to use a different image version for the migration job, you can specify it by passing extra arguments to the controller:
|
||||
|
||||
```shell
|
||||
helm upgrade kamaji clastix/kamaji -n kamaji-system
|
||||
helm upgrade kamaji clastix/kamaji --version ${CHART_VERSION} -n kamaji-system
|
||||
--set extraArgs[0]=--migrate-image=custom/kamaji:version`
|
||||
```
|
||||
|
||||
|
||||
33
docs/content/guides/pausing.md
Normal file
33
docs/content/guides/pausing.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Pausing Reconciliations
|
||||
|
||||
Kamaji follows the Kubernetes Operator pattern, which includes implementing a reconciliation loop.
|
||||
This loop continuously reacts to events such as creation, updates, and deletions of resources.
|
||||
|
||||
To temporarily disable reconciliation for a resource, you can use the following annotation:
|
||||
> `kamaji.clastix.io/paused`
|
||||
|
||||
!!! info "Annotation value"
|
||||
The annotation key is sufficient on its own: no value is required.
|
||||
Its mere presence disables controller reconciliations.
|
||||
|
||||
## Pausing `TenantControlPlane` reconciliations
|
||||
|
||||
When you add the `kamaji.clastix.io/paused` annotation to a TenantControlPlane object,
|
||||
Kamaji will halt all reconciliation processes for that object.
|
||||
|
||||
This affects **all controllers**, including:
|
||||
|
||||
- The primary controller responsible for provisioning resources in the management cluster
|
||||
- Secondary (soot) controllers responsible for bootstrapping the control plane, deploying addons, and managing any additional resources handled by Kamaji.
|
||||
|
||||
## Pausing Secret rotation
|
||||
|
||||
Kamaji automatically generates and manages several `Secret` resources, such as:
|
||||
|
||||
- `x509` certificates
|
||||
- `kubeconfig` credentials
|
||||
|
||||
These secrets are automatically rotated by Kamaji's built-in **Certificate Lifecycle** feature.
|
||||
|
||||
To temporarily disable secret rotation for these resources,
|
||||
apply the `kamaji.clastix.io/paused` annotation to the corresponding object.
|
||||
46
docs/content/guides/terraform.md
Normal file
46
docs/content/guides/terraform.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Terraform
|
||||
|
||||
While [Cluster API](https://github.com/kubernetes-sigs/cluster-api) is a common approach for managing Kubernetes infrastructure declaratively, there are situations where Cluster API may not be suitable or desired. This can occur for various reasons, such as:
|
||||
|
||||
- The need to keep control plane management separate from infrastructure management
|
||||
- When the infrastructure provider hosting worker nodes lacks native Cluster API support
|
||||
- Existing Terraform-based infrastructure workflows that need integration
|
||||
- Specific compliance or organizational requirements
|
||||
|
||||
In these scenarios, an alternative approach is to provision worker nodes using [`yaki`](https://goyaki.clastix.io/), a wrapper around the standard `kubeadm` utility developed and maintained by [Clastix Labs](https://github.com/clastix).
|
||||
|
||||
## How It Works
|
||||
|
||||
The workflow combines [Terraform](https://developer.hashicorp.com/terraform) for infrastructure provisioning with `yaki` for Kubernetes node bootstrapping:
|
||||
|
||||
1. **Terraform** provisions the virtual machines on your chosen infrastructure
|
||||
2. **`yaki`** installs all required Kubernetes dependencies on each machine
|
||||
3. **Bootstrap tokens** automatically join the machines to your Kamaji tenant control plane
|
||||
|
||||
## Terraform Modules
|
||||
|
||||
The [terraform-kamaji-node-pool](https://github.com/clastix/terraform-kamaji-node-pool) repository provides comprehensive Terraform modules for provisioning Kubernetes worker nodes across multiple cloud providers. The repository is structured to support various infrastructure providers with Terraform support, including:
|
||||
|
||||
- **AWS** - Auto Scaling Groups with automatic scaling
|
||||
- **Azure** - Virtual Machine Scale Sets *(planned)*
|
||||
- **vSphere** - Enterprise-grade virtual machines
|
||||
- **Proxmox** - Direct VM management on Proxmox VE
|
||||
- **vCloud** - Multi-tenant VMs on VMware Cloud Director
|
||||
|
||||
### Key Features
|
||||
|
||||
- **Multi-cloud support** with consistent interfaces across providers
|
||||
- **Automatic bootstrap token management** for secure cluster joining
|
||||
- **Shared cloud-init templates** for consistent node configuration
|
||||
- **Ready-to-use provider implementations** with example configurations
|
||||
- **Modular architecture** allowing custom integrations
|
||||
|
||||
### Getting Started
|
||||
|
||||
For detailed usage instructions, see the [project documentation](https://github.com/clastix/terraform-kamaji-node-pool#readme).
|
||||
|
||||
!!! tip "Production Considerations"
|
||||
The Terraform modules serve as comprehensive examples and starting points for Kamaji integration. While they include production-ready features like security groups, IAM policies, and anti-affinity rules, you should customize them to meet your specific security, compliance, and operational requirements before using them in production environments.
|
||||
|
||||
!!! note "Bootstrap Security"
|
||||
The modules automatically generate secure bootstrap tokens with limited lifetime and scope. These tokens are used only for the initial node join process and are cleaned up after successful tenent cluster formation.
|
||||
127
docs/content/llms.txt
Normal file
127
docs/content/llms.txt
Normal file
@@ -0,0 +1,127 @@
|
||||
# Kamaji
|
||||
|
||||
> Kamaji is the Control Plane Manager for Kubernetes, enabling multi-tenant, upstream-compliant clusters as pods in a central management cluster. Developed and maintained by Clastix, Kamaji brings operational efficiency, strong isolation, and cloud-native flexibility to Kubernetes at scale.
|
||||
|
||||
Kamaji runs Kubernetes control planes as pods in a central Management Cluster, enabling fast, scalable, and cost-effective multi-tenancy. Each Tenant Cluster is fully isolated, CNCF-compliant, and managed declaratively using Kubernetes CRDs. Kamaji integrates with Cluster API, supports GitOps workflows, and offers enterprise-grade add-ons for advanced use cases.
|
||||
Kamaji is like a fleet of Site Reliability Engineers with expertise codified into its logic, working 24/7 to keep your Control Planes up and running.
|
||||
|
||||
## Architecture
|
||||
|
||||
- **Management Cluster:** Hosts Kamaji and all Tenant Control Planes as pods, leveraging Kubernetes reliability and scalability.
|
||||
- **Tenant Clusters:** User-facing clusters, each with a dedicated control plane running in the Management Cluster. Full isolation between tenants.
|
||||
- **Tenant Worker Nodes:** Machines that join Tenant Clusters, running only tenant workloads for strong security and resource isolation.
|
||||
|
||||
## Main Features
|
||||
|
||||
- Multi-Tenancy: Deploy multiple Kubernetes control planes as pods within a single management cluster. Each control plane operates independently, ensuring complete isolation between tenants.
|
||||
- Upstream Kubernetes: Uses unmodified upstream Kubernetes components and leverages kubeadm, the default tool for cluster bootstrapping and management.
|
||||
- Infrastructure Agnostic: Connect worker nodes from any infrastructure provider. Supports bare metal, virtual machines, and cloud instances, allowing hybrid and multi-cloud deployments.
|
||||
- Resource Optimization: Control planes run as pods, sharing the management cluster's resources efficiently. Scale control planes independently based on actual usage patterns and requirements.
|
||||
- Cluster API Integration: Seamlessly integrates with Cluster API providers for automated infrastructure provisioning and lifecycle management across different environments.
|
||||
- High Availability: Supports multi-node control plane deployments with distributed etcd clusters. Includes automated failover and recovery mechanisms for production workloads.
|
||||
- Full CNCF compliance and seamless integration with Cluster API, GitOps, and IaC tools.
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Private Cloud: Optimize your data center resources by running multiple Kubernetes control planes. Perfect for organizations that need complete control over their infrastructure while maintaining strict isolation between different business units.
|
||||
- Public Cloud: Build independent public cloud offerings with Kubernetes-as-a-Service capabilities. Provide the same user experience as major cloud providers while maintaining full control over the infrastructure and operational costs.
|
||||
- Bare Metal: Maximize hardware utilization by running multiple control planes on your physical infrastructure. Ideal for environments where direct hardware access, network performance, and data locality are critical.
|
||||
- Edge Computing: Run lightweight Kubernetes clusters at the edge while managing their control planes centrally. Reduce the hardware footprint at edge locations by keeping control planes in your central management cluster.
|
||||
- Platform Engineering: Build internal Kubernetes platforms with standardized cluster provisioning and management. Enable self-service capabilities while maintaining centralized control and governance over all clusters.
|
||||
- Bring Your Own Cloud: Create your own managed Kubernetes service using standard upstream components. Provide dedicated clusters to your users while maintaining operational efficiency through centralized control plane management.
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
- What does Kamaji mean? Kamaji is named after Kamajī (かまじ) from the Japanese movie Spirited Away. Kamajī is the boiler room operator who efficiently manages the bathhouse's water system—just like Kamaji manages Kubernetes clusters!
|
||||
- Is Kamaji another Kubernetes distribution? No, Kamaji is a Kubernetes Operator that provides managed Kubernetes clusters as a service, leveraging kubeadm for conformant CNCF Kubernetes clusters.
|
||||
- How is it different from typical solutions? Kamaji runs the Control Plane as regular pods in the Management Cluster, offering it as a service and making it more cost-effective and easier to operate at scale.
|
||||
- How does it compare to public cloud services? Kamaji gives you full control over your Kubernetes infrastructure, offering consistency across cloud, data center, and edge while simplifying centralized operations.
|
||||
- How does it differ from Cluster API? They complement each other: Kamaji simplifies Control Plane management, while Cluster API handles infrastructure abstraction and lifecycle management.
|
||||
- Why Kamaji when Capsule exists? While Capsule provides a single control plane with isolated namespaces, Kamaji provides dedicated control planes when tenants need full cluster admin permissions.
|
||||
- Do you provide support? Yes, Clastix offers subscription-based, enterprise-grade support plans for Kamaji. Please contact us to discuss your support needs.
|
||||
|
||||
## About Clastix
|
||||
|
||||
Clastix is a technology company specializing in cloud-native solutions and Kubernetes platforms, with a strong history of delivering advanced, production-grade systems for cloud computing builders. Clastix has collaborated with a number of CSPs worldwide, enabling them to build resilient, scalable cloud infrastructures aligned with modern digital requirements. Beyond the development of Kamaji, Clastix delivers complementary services including integration with enterprise ecosystems, strategic consulting for infrastructure transformation, and training in cloud-native and Kubernetes best practices.
|
||||
|
||||
## Releases and Versions
|
||||
|
||||
Kamaji versions are available in different types of release artifacts.
|
||||
|
||||
### Latest Releases
|
||||
|
||||
CI is responsible for building OCI and Helm Charts for every commit in the main branch (master). The latest artifacts are aimed at rapid development tests and evaluation processes.
|
||||
|
||||
### Edge Releases
|
||||
|
||||
Edge Release artifacts are published on a monthly basis as part of the open source project. Edge Releases are generally considered production ready.
|
||||
|
||||
### Stable Releases
|
||||
|
||||
Clastix Labs no longer provides release artifacts following its own semantic versioning: this choice has been made to help monetize Clastix in the development and maintenance of the Kamaji project. Stable artifacts such as OCI (containers) and Helm Charts are available on a subscription basis maintained by CLASTIX.
|
||||
|
||||
## Documentation
|
||||
|
||||
### Getting Started
|
||||
|
||||
- [Getting Started](https://github.com/clastix/kamaji/blob/master/docs/content/getting-started/index.md): Step-by-step setup for different environments
|
||||
- [Getting Started on a Generic Infrastructure](https://github.com/clastix/kamaji/blob/master/docs/content/getting-started/kamaji-generic.md): The process of creating a working Kamaji setup on a generic infrastructure.
|
||||
|
||||
### Concepts
|
||||
|
||||
- [Concepts](https://github.com/clastix/kamaji/blob/master/docs/content/concepts/index.md): Core ideas and architecture
|
||||
|
||||
### Cluster API Support
|
||||
|
||||
- [Cluster API Support](https://github.com/clastix/kamaji/blob/master/docs/content/cluster-api/index.md): How Kamaji supports Cluster APIs for declarative cluster provisioning
|
||||
- [Kamaji Cluster API Provider](https://github.com/clastix/kamaji/blob/master/docs/content/cluster-api/control-plane-provider.md): Kamaji can act as a Cluster API Control Plane provider
|
||||
- [Kamaji Cluster API Class](https://github.com/clastix/kamaji/blob/master/docs/content/cluster-api/cluster-class.md): Kamaji supports ClusterClass, a simple way to create many clusters of a similar shape.
|
||||
- [Kamaji Cluster Autoscaler](https://github.com/clastix/kamaji/blob/master/docs/content/cluster-api/cluster-autoscaler.md): Kamaji supports the Cluster Autoscaler through Cluster API.
|
||||
- [Kamaji Cluster API Infra Providers](https://github.com/clastix/kamaji/blob/master/docs/content/cluster-api/other-providers.md): Kamaji offers seamless integration with the most popular Cluster API Infrastructure Providers
|
||||
|
||||
### Guides
|
||||
|
||||
- [Kamaji Alternative Datastores](https://github.com/clastix/kamaji/blob/master/docs/content/guides/alternative-datastore.md): Kamaji offers the possibility of using different storage systems
|
||||
- [Kamaji Backup & Restore](https://github.com/clastix/kamaji/blob/master/docs/content/guides/backup-and-restore.md): How to back up and restore TCP resources on the Management Cluster using Velero
|
||||
- [Kamaji Certificates Lifecycle](https://github.com/clastix/kamaji/blob/master/docs/content/guides/certs-lifecycle.md): Kamaji is able to automatically rotate cluster certificates
|
||||
- [Kamaji Datastore Migration](https://github.com/clastix/kamaji/blob/master/docs/content/guides/datastore-migration.md): Kamaji live migrates Tenant data from one datastore to another
|
||||
- [Kamaji GitOps Approach](https://github.com/clastix/kamaji/blob/master/docs/content/guides/gitops.md): Describes a declarative way to deploy Kubernetes add-ons across multiple Tenant Clusters, the GitOps way
|
||||
- [Tenant Cluster Upgrade](https://github.com/clastix/kamaji/blob/master/docs/content/guides/upgrade.md): How to upgrade a Tenant Cluster
|
||||
- [Tenant Control Plane Monitoring](https://github.com/clastix/kamaji/blob/master/docs/content/guides/monitoring.md): How to monitor a Tenant Control Plane
|
||||
- [Terraform Support](https://github.com/clastix/kamaji/blob/master/docs/content/guides/terraform.md): How Kamaji supports Infrastructure as Code (IaC)
|
||||
- [Benchmark](https://github.com/clastix/kamaji/blob/master/docs/content/reference/benchmark.md): Kamaji has been designed to operate a large scale of Kubernetes Tenant Control Plane resources
|
||||
- [CNCF Conformance](https://github.com/clastix/kamaji/blob/master/docs/content/reference/conformance.md): All the "Tenant Clusters" built with Kamaji are CNCF conformant
|
||||
- [Releases and Versions](https://github.com/clastix/kamaji/blob/master/docs/content/reference/versioning.md): Kamaji versions are available in different types of release artifacts
|
||||
- [API Reference](https://github.com/clastix/kamaji/blob/master/docs/content/reference/api.md): Kamaji Custom Resources full API documentation
|
||||
|
||||
## GitHub
|
||||
|
||||
- [Readme](https://github.com/clastix/kamaji/blob/master/README.md): GitHub Readme file
|
||||
- [License](https://github.com/clastix/kamaji/blob/master/LICENSE): Apache 2.0 license
|
||||
|
||||
## Support
|
||||
|
||||
- [Contact Clastix](https://clastix.io/contact): Commercial support and inquiries
|
||||
- [Kubernetes Slack #kamaji](https://kubernetes.slack.com/archives/C03GLTTMWNN): Community chat
|
||||
|
||||
## API Reference
|
||||
|
||||
- [TenantControlPlane API](https://github.com/clastix/kamaji/blob/master/docs/content/reference/api.md#tenantcontrolplane): Full spec for the TenantControlPlane resource
|
||||
- [Datastore API](https://github.com/clastix/kamaji/blob/master/docs/content/reference/api.md#datastore): Full spec for the Datastore resource
|
||||
|
||||
## Adopters
|
||||
|
||||
- [Adopters List](https://github.com/clastix/kamaji/blob/master/ADOPTERS.md): Organizations using Kamaji
|
||||
|
||||
## Project Status
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## User Quote
|
||||
|
||||
> "Kamaji works exactly as expected: it's 'simple', efficient, scalable, and I especially appreciate how Clastix has always been available for technical discussions and support throughout these two years of collaboration."
|
||||
>
|
||||
> — Jeremie Monsinjon, Head of Containers @ OVHCloud
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +1,46 @@
|
||||
# Releases and Versions
|
||||
|
||||
[Clastix Labs](https://github.com/clastix) organization publishes Kamaji's versions that correspond to specific project milestones and sets of new features. These versions are available in different types of release artifacts.
|
||||
[Clastix Labs](https://github.com/clastix) organization publishes Kamaji's versions that correspond to specific project milestones and sets of new features.
|
||||
These versions are available in different types of release artifacts.
|
||||
|
||||
## Types of release artifacts
|
||||
|
||||
### Latest Releases
|
||||
|
||||
CI is responsible for building OCI and Helm Chart for every commit in the main branch (`master`):
|
||||
The latest artifacts are aimed for rapid development tests and evaluation process.
|
||||
|
||||
Usage of the said artefacts is not suggested for production use-case due to missing version pinning of artefacts:
|
||||
|
||||
- `latest` for OCI image (e.g.: `docker.io/clastix/kamaji:latest`)
|
||||
- `0.0.0+latest` for the Helm Chart managed by CLASTIX (`https://clastix.github.io/charts`)
|
||||
|
||||
### Edge Releases
|
||||
|
||||
Edge Release artifacts are published on a monthly basis as part of the open source project. Versioning follows the form `edge-{year}.{month}.{incremental}` where incremental refers to the monthly release. For example, `edge-24.7.1` is the first edge release shipped in July 2024. The full list of edge release artifacts can be found on the Kamaji's GitHub [releases page](https://github.com/clastix/kamaji/releases).
|
||||
Edge Release artifacts are published on a monthly basis as part of the open source project.
|
||||
Versioning follows the form `edge-{year}.{month}.{incremental}` where incremental refers to the monthly release.
|
||||
For example, `edge-24.7.1` is the first edge release shipped in July 2024.
|
||||
The full list of edge release artifacts can be found on the Kamaji's GitHub [releases page](https://github.com/clastix/kamaji/releases).
|
||||
|
||||
Edge Release artifacts contain the code in from the main branch at the point in time when they were cut. This means they always have the latest features and fixes, and have undergone automated testing as well as maintainer code review. Edge Releases may involve partial features that are later modified or backed out. They may also involve breaking changes, of course, we do our best to avoid this. Edge Releases are generally considered production ready, and the project will mark specific releases as “_not recommended_” if bugs are discovered after release.
|
||||
Edge Release artifacts contain the code in from the main branch at the point in time when they were cut.
|
||||
This means they always have the latest features and fixes, and have undergone automated testing as well as maintainer code review.
|
||||
Edge Releases may involve partial features that are later modified or backed out.
|
||||
They may also involve breaking changes, of course, we do our best to avoid this.
|
||||
|
||||
| Kamaji | Management Cluster | Tenant Cluster |
|
||||
|--------------|--------------------|----------------------|
|
||||
| edge-24.12.1 | v1.22+ | [v1.29.0 .. v1.31.4] |
|
||||
Edge Releases are generally considered production ready and the project will mark specific releases as _"not recommended"_ if bugs are discovered after release.
|
||||
|
||||
| Kamaji | Management Cluster | Tenant Cluster |
|
||||
|-------------|--------------------|----------------------|
|
||||
| edge-25.4.1 | v1.22+ | [v1.30.0 .. v1.33.0] |
|
||||
|
||||
|
||||
Using Edge Release artifacts and reporting bugs helps us ensure a rapid pace of development and is a great way to help maintainers. We publish edge release guidance as part of the release notes and strive to always provide production-ready artifacts.
|
||||
Using Edge Release artifacts and reporting bugs helps us ensure a rapid pace of development and is a great way to help maintainers.
|
||||
We publish edge release guidance as part of the release notes and strive to always provide production-ready artifacts.
|
||||
|
||||
### Stable Releases
|
||||
|
||||
Stable Release artifacts of Kamaji follow semantic versioning, whereby changes in major version denote large feature additions and possible breaking changes and changes in minor versions denote safe upgrades without breaking changes. As of July 2024, [Clastix Labs](https://github.com/clastix) does no longer provide stable release artifacts.
|
||||
As of July 2024, [Clastix Labs](https://github.com/clastix) does no longer provide release artifacts following its own semantic versioning:
|
||||
this choice has been put in place to help monetize CLASTIX in the development and maintenance of the Kamaji project.
|
||||
|
||||
Stable Release artifacts are offered now on a subscription basis by [CLASTIX](https://clastix.io), the main Kamaji project contributor. Learn more about the available [Subscription Plans](https://clastix.io/support/).
|
||||
Stable artifacts such as OCI (containers) and Helm Chart ones are available on a subscription basis maintained by [CLASTIX](https://clastix.io):
|
||||
learn more about the available [Subscription Plans](https://clastix.io/support/).
|
||||
|
||||
@@ -71,13 +71,15 @@ nav:
|
||||
- 'Guides':
|
||||
- guides/index.md
|
||||
- guides/alternative-datastore.md
|
||||
- guides/gitops.md
|
||||
- guides/upgrade.md
|
||||
- guides/datastore-migration.md
|
||||
- guides/backup-and-restore.md
|
||||
- guides/monitoring.md
|
||||
- guides/console.md
|
||||
- guides/certs-lifecycle.md
|
||||
- guides/pausing.md
|
||||
- guides/datastore-migration.md
|
||||
- guides/gitops.md
|
||||
- guides/console.md
|
||||
- guides/upgrade.md
|
||||
- guides/monitoring.md
|
||||
- guides/terraform.md
|
||||
- guides/contribute.md
|
||||
- 'Reference':
|
||||
- reference/index.md
|
||||
|
||||
@@ -223,4 +223,12 @@
|
||||
/* Dark Mode Icon Color */
|
||||
[data-md-color-scheme="slate"] .tx-card_icon svg {
|
||||
fill: #ffffff;
|
||||
}
|
||||
|
||||
.user-quote {
|
||||
font-size: 1.2em;
|
||||
font-style: italic;
|
||||
margin: 2em 0;
|
||||
border-left: 4px solid #D81D56 !important;
|
||||
padding-left: 1em;
|
||||
}
|
||||
@@ -24,6 +24,18 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- User Quote Section -->
|
||||
<section class="tx-section tx-section--alternate">
|
||||
<div class="md-grid md-typeset">
|
||||
<h2 class="tx-section-title">What Users Say</h2>
|
||||
<blockquote class="user-quote">
|
||||
"Kamaji works exactly as expected: it's simple, efficient, scalable, and I especially appreciate how Clastix has always been available for technical discussions and support throughout these two years of collaboration."
|
||||
<br><br>
|
||||
<span style="font-weight:bold; font-size:1em;">— Jérémie Monsinjon, Head of Containers @OVHCloud</span>
|
||||
</blockquote>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Highlights Section -->
|
||||
<section class="tx-section tx-section--alternate">
|
||||
<div class="md-grid md-typeset">
|
||||
|
||||
10
docs/templates/reference-cr.tmpl
vendored
10
docs/templates/reference-cr.tmpl
vendored
@@ -1,5 +1,8 @@
|
||||
# API Reference
|
||||
|
||||
This section contains the Kamaji Customer Resource Definitions,
|
||||
as well as the Cluster API Control Plane provider ones.
|
||||
|
||||
Packages:
|
||||
{{range .Groups}}
|
||||
- [{{.Group}}/{{.Version}}](#{{ anchorize (printf "%s/%s" .Group .Version) }})
|
||||
@@ -8,7 +11,7 @@ Packages:
|
||||
{{- range .Groups }}
|
||||
{{- $group := . }}
|
||||
|
||||
# {{.Group}}/{{.Version}}
|
||||
## {{.Group}}/{{.Version}}
|
||||
|
||||
Resource Types:
|
||||
{{range .Kinds}}
|
||||
@@ -17,15 +20,14 @@ Resource Types:
|
||||
|
||||
{{range .Kinds}}
|
||||
{{$kind := .}}
|
||||
## {{.Name}}
|
||||
### {{.Name}}
|
||||
|
||||
{{range .Types}}
|
||||
|
||||
{{if not .IsTopLevel}}
|
||||
### {{.Name}}
|
||||
<span id="{{ anchorize .Name }}">`{{.Name}}`</span>
|
||||
{{end}}
|
||||
|
||||
|
||||
{{.Description}}
|
||||
|
||||
<table>
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -137,23 +139,49 @@ var _ = Describe("starting a kind worker with kubeadm", func() {
|
||||
})
|
||||
|
||||
By("enabling br_netfilter", func() {
|
||||
exitCode, _, err := workerContainer.Exec(ctx, []string{"modprobe", "br_netfilter"})
|
||||
exitCode, stdout, err := workerContainer.Exec(ctx, []string{"modprobe", "br_netfilter"})
|
||||
|
||||
Expect(exitCode).To(Equal(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
out, _ := io.ReadAll(stdout)
|
||||
if len(out) > 0 {
|
||||
_, _ = fmt.Fprintln(GinkgoWriter, "modprobe failed: "+string(out))
|
||||
}
|
||||
|
||||
if exitCode != 0 {
|
||||
_, _ = fmt.Fprintln(GinkgoWriter, "modprobe exit code: "+strconv.FormatUint(uint64(exitCode), 10))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(GinkgoWriter, "modprobe error: "+err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
By("disabling swapp", func() {
|
||||
exitCode, _, err := workerContainer.Exec(ctx, []string{"swapoff", "-a"})
|
||||
By("disabling swap", func() {
|
||||
exitCode, stdout, err := workerContainer.Exec(ctx, []string{"swapoff", "-a"})
|
||||
|
||||
Expect(exitCode).To(Equal(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
out, _ := io.ReadAll(stdout)
|
||||
if len(out) > 0 {
|
||||
_, _ = fmt.Fprintln(GinkgoWriter, "swapoff failed: "+string(out))
|
||||
}
|
||||
|
||||
if exitCode != 0 {
|
||||
_, _ = fmt.Fprintln(GinkgoWriter, "swapoff exit code: "+strconv.FormatUint(uint64(exitCode), 10))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
_, _ = fmt.Fprintln(GinkgoWriter, "swapoff error: "+err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
By("executing the command in the worker node", func() {
|
||||
cmds := append(strings.Split(strings.TrimSpace(joinCommandBuffer.String()), " "), "--ignore-preflight-errors=SystemVerification")
|
||||
cmds := append(strings.Split(strings.TrimSpace(joinCommandBuffer.String()), " "), "--ignore-preflight-errors=SystemVerification,FileExisting")
|
||||
|
||||
exitCode, stdout, err := workerContainer.Exec(ctx, cmds)
|
||||
|
||||
out, _ := io.ReadAll(stdout)
|
||||
if len(out) > 0 {
|
||||
_, _ = fmt.Fprintln(GinkgoWriter, "executing failed: "+string(out))
|
||||
}
|
||||
|
||||
exitCode, _, err := workerContainer.Exec(ctx, cmds)
|
||||
Expect(exitCode).To(Equal(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
103
go.mod
103
go.mod
@@ -6,36 +6,37 @@ 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 v28.1.1+incompatible
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/docker/docker v28.3.2+incompatible
|
||||
github.com/go-logr/logr v1.4.3
|
||||
github.com/go-pg/pg/v10 v10.14.0
|
||||
github.com/go-sql-driver/mysql v1.9.2
|
||||
github.com/go-sql-driver/mysql v1.9.3
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/juju/mutex/v2 v2.0.0
|
||||
github.com/nats-io/nats.go v1.41.2
|
||||
github.com/nats-io/nats.go v1.43.0
|
||||
github.com/onsi/ginkgo/v2 v2.23.4
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/spf13/pflag v1.0.6
|
||||
github.com/spf13/pflag v1.0.7
|
||||
github.com/spf13/viper v1.20.1
|
||||
github.com/testcontainers/testcontainers-go v0.37.0
|
||||
github.com/testcontainers/testcontainers-go v0.38.0
|
||||
go.etcd.io/etcd/api/v3 v3.5.21
|
||||
go.etcd.io/etcd/client/v3 v3.5.21
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.5.0
|
||||
k8s.io/api v0.33.0
|
||||
k8s.io/apimachinery v0.33.0
|
||||
k8s.io/apiserver v0.33.0
|
||||
k8s.io/client-go v0.33.0
|
||||
k8s.io/api v0.33.1
|
||||
k8s.io/apimachinery v0.33.1
|
||||
k8s.io/apiserver v0.33.1
|
||||
k8s.io/client-go v0.33.1
|
||||
k8s.io/cluster-bootstrap v0.0.0
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kubelet v0.0.0
|
||||
k8s.io/kubernetes v1.33.0
|
||||
k8s.io/kubernetes v1.33.2
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
|
||||
sigs.k8s.io/controller-runtime v0.20.4
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -51,6 +52,8 @@ require (
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/coredns/caddy v1.1.1 // indirect
|
||||
@@ -62,7 +65,7 @@ require (
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/ebitengine/purego v0.8.2 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||
@@ -104,7 +107,6 @@ require (
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/go-archive v0.1.0 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/moby/sys/user v0.4.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
@@ -122,12 +124,11 @@ require (
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
@@ -177,15 +178,15 @@ require (
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.1 // indirect
|
||||
k8s.io/cli-runtime v0.0.0 // indirect
|
||||
k8s.io/cloud-provider v0.0.0 // indirect
|
||||
k8s.io/component-base v0.33.0 // indirect
|
||||
k8s.io/component-helpers v0.33.0 // indirect
|
||||
k8s.io/controller-manager v0.33.0 // indirect
|
||||
k8s.io/cri-api v0.33.0 // indirect
|
||||
k8s.io/component-base v0.33.1 // indirect
|
||||
k8s.io/component-helpers v0.33.1 // indirect
|
||||
k8s.io/controller-manager v0.33.1 // indirect
|
||||
k8s.io/cri-api v0.33.1 // indirect
|
||||
k8s.io/cri-client v0.0.0 // indirect
|
||||
k8s.io/kms v0.33.0 // indirect
|
||||
k8s.io/kms v0.33.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/kube-proxy v0.0.0 // indirect
|
||||
k8s.io/system-validators v1.9.1 // indirect
|
||||
@@ -200,35 +201,35 @@ require (
|
||||
)
|
||||
|
||||
replace (
|
||||
k8s.io/api => k8s.io/api v0.33.0
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.33.0
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.33.0
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.33.0
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.33.0
|
||||
k8s.io/client-go => k8s.io/client-go v0.33.0
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.33.0
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.33.0
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.33.0
|
||||
k8s.io/component-base => k8s.io/component-base v0.33.0
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.33.0
|
||||
k8s.io/controller-manager => k8s.io/controller-manager v0.33.0
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.33.0
|
||||
k8s.io/cri-client => k8s.io/cri-client v0.33.0
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.33.0
|
||||
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.33.0
|
||||
k8s.io/endpointslice => k8s.io/endpointslice v0.33.0
|
||||
k8s.io/externaljwt => k8s.io/externaljwt v0.33.0
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.33.0
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.33.0
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.33.0
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.33.0
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.33.0
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.33.0
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.33.0
|
||||
k8s.io/metrics => k8s.io/metrics v0.33.0
|
||||
k8s.io/mount-utils => k8s.io/mount-utils v0.33.0
|
||||
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.33.0
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.33.0
|
||||
k8s.io/api => k8s.io/api v0.33.1
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.33.1
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.33.1
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.33.1
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.33.1
|
||||
k8s.io/client-go => k8s.io/client-go v0.33.1
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.33.1
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.33.1
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.33.1
|
||||
k8s.io/component-base => k8s.io/component-base v0.33.1
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.33.1
|
||||
k8s.io/controller-manager => k8s.io/controller-manager v0.33.1
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.33.1
|
||||
k8s.io/cri-client => k8s.io/cri-client v0.33.1
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.33.1
|
||||
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.33.1
|
||||
k8s.io/endpointslice => k8s.io/endpointslice v0.33.1
|
||||
k8s.io/externaljwt => k8s.io/externaljwt v0.33.1
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.33.1
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.33.1
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.33.1
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.33.1
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.33.1
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.33.1
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.33.1
|
||||
k8s.io/metrics => k8s.io/metrics v0.33.1
|
||||
k8s.io/mount-utils => k8s.io/mount-utils v0.33.1
|
||||
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.33.1
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.33.1
|
||||
)
|
||||
|
||||
replace github.com/JamesStewy/go-mysqldump => github.com/vtoma/go-mysqldump v1.0.0
|
||||
|
||||
107
go.sum
107
go.sum
@@ -28,6 +28,10 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clastix/kamaji-telemetry v1.0.0 h1:/s7TVsyQpunD+cBKIaWmZ1yCXXYXgf4uQ4TeXio4moY=
|
||||
github.com/clastix/kamaji-telemetry v1.0.0/go.mod h1:yhK/I0qEmKQw4mtEZRUnQfjsbbrIZtuR/XXISBrrETU=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
@@ -52,16 +56,16 @@ 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 v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
|
||||
github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v28.3.2+incompatible h1:wn66NJ6pWB1vBZIilP8G3qQPqHy5XymfYn5vsqeA5oA=
|
||||
github.com/docker/docker v28.3.2+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=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
|
||||
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
||||
@@ -80,8 +84,8 @@ github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXE
|
||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||
@@ -100,8 +104,8 @@ github.com/go-pg/pg/v10 v10.14.0 h1:giXuPsJaWjzwzFJTxy39eBgGE44jpqH1jwv0uI3kBUU=
|
||||
github.com/go-pg/pg/v10 v10.14.0/go.mod h1:6kizZh54FveJxw9XZdNg07x7DDBWNsQrSiJS04MLwO8=
|
||||
github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU=
|
||||
github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo=
|
||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
||||
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
@@ -229,8 +233,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nats-io/nats.go v1.41.2 h1:5UkfLAtu/036s99AhFRlyNDI1Ieylb36qbGjJzHixos=
|
||||
github.com/nats-io/nats.go v1.41.2/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nats.go v1.43.0 h1:uRFZ2FEoRvP64+UUhaTokyS18XBCR/xM2vQZKO4i8ug=
|
||||
github.com/nats-io/nats.go v1.43.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
|
||||
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
@@ -275,8 +279,8 @@ github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsF
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs=
|
||||
github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
||||
@@ -289,8 +293,9 @@ github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
|
||||
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
|
||||
@@ -311,8 +316,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
||||
github.com/stretchr/testify v1.10.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.37.0 h1:L2Qc0vkTw2EHWQ08djon0D2uw7Z/PtHS/QzZZ5Ra/hg=
|
||||
github.com/testcontainers/testcontainers-go v0.37.0/go.mod h1:QPzbxZhQ6Bclip9igjLFj6z0hs01bU8lrl2dHQmgFGM=
|
||||
github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw=
|
||||
github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w=
|
||||
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=
|
||||
@@ -481,44 +486,44 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
||||
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
||||
k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs=
|
||||
k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc=
|
||||
k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
|
||||
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/apiserver v0.33.0 h1:QqcM6c+qEEjkOODHppFXRiw/cE2zP85704YrQ9YaBbc=
|
||||
k8s.io/apiserver v0.33.0/go.mod h1:EixYOit0YTxt8zrO2kBU7ixAtxFce9gKGq367nFmqI8=
|
||||
k8s.io/cli-runtime v0.33.0 h1:Lbl/pq/1o8BaIuyn+aVLdEPHVN665tBAXUePs8wjX7c=
|
||||
k8s.io/cli-runtime v0.33.0/go.mod h1:QcA+r43HeUM9jXFJx7A+yiTPfCooau/iCcP1wQh4NFw=
|
||||
k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
|
||||
k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
|
||||
k8s.io/cloud-provider v0.33.0 h1:nVU2Q9QK7O50yaNx+pE61oDPqflsSsKygN43f5js9+I=
|
||||
k8s.io/cloud-provider v0.33.0/go.mod h1:2reyEBbsimZJKHF325vxLBD5fcJGNeJHeLjJ+jGM8Qg=
|
||||
k8s.io/cluster-bootstrap v0.33.0 h1:a1njmBk8ha+TNK8HqfLkuMyC6Q9qvnm5eZzBLpwEW/A=
|
||||
k8s.io/cluster-bootstrap v0.33.0/go.mod h1:YL0riHER19bZOT5Pdpl1ynbypadaEoWfg3Ywnl0Pb5s=
|
||||
k8s.io/component-base v0.33.0 h1:Ot4PyJI+0JAD9covDhwLp9UNkUja209OzsJ4FzScBNk=
|
||||
k8s.io/component-base v0.33.0/go.mod h1:aXYZLbw3kihdkOPMDhWbjGCO6sg+luw554KP51t8qCU=
|
||||
k8s.io/component-helpers v0.33.0 h1:0AdW0A0mIgljLgtG0hJDdJl52PPqTrtMgOgtm/9i/Ys=
|
||||
k8s.io/component-helpers v0.33.0/go.mod h1:9SRiXfLldPw9lEEuSsapMtvT8j/h1JyFFapbtybwKvU=
|
||||
k8s.io/controller-manager v0.33.0 h1:O9LnTjffOe62d66gMcKLuPXsBjY5sqETWEIzg+DVL8w=
|
||||
k8s.io/controller-manager v0.33.0/go.mod h1:vQwAQnroav4+UyE2acW1Rj6CSsHPzr2/018kgRLYqlI=
|
||||
k8s.io/cri-api v0.33.0 h1:YyGNgWmuSREqFPlP3XCstlHLilYdW898KwtKoaTYwBs=
|
||||
k8s.io/cri-api v0.33.0/go.mod h1:OLQvT45OpIA+tv91ZrpuFIGY+Y2Ho23poS7n115Aocs=
|
||||
k8s.io/cri-client v0.33.0 h1:NLB4SKWQqJ2jPtbbdKFY2gEEw/GKSKifSqUf4m/SwSs=
|
||||
k8s.io/cri-client v0.33.0/go.mod h1:ZIbzmm5ByB0cz0nc5qUlgKZwi1KivOGVXgearqF27cU=
|
||||
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
|
||||
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
|
||||
k8s.io/apiextensions-apiserver v0.33.1 h1:N7ccbSlRN6I2QBcXevB73PixX2dQNIW0ZRuguEE91zI=
|
||||
k8s.io/apiextensions-apiserver v0.33.1/go.mod h1:uNQ52z1A1Gu75QSa+pFK5bcXc4hq7lpOXbweZgi4dqA=
|
||||
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
|
||||
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
|
||||
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
|
||||
k8s.io/cli-runtime v0.33.1 h1:TvpjEtF71ViFmPeYMj1baZMJR4iWUEplklsUQ7D3quA=
|
||||
k8s.io/cli-runtime v0.33.1/go.mod h1:9dz5Q4Uh8io4OWCLiEf/217DXwqNgiTS/IOuza99VZE=
|
||||
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
|
||||
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
|
||||
k8s.io/cloud-provider v0.33.1 h1:nOmby9fIKCBJr9fNKXpLK5IBbS1snX82+JIxfxGvhI8=
|
||||
k8s.io/cloud-provider v0.33.1/go.mod h1:2lvWqPsvBOzbtGWjGfVDX/ttpvSeI9ZdB8d4TbYnt9s=
|
||||
k8s.io/cluster-bootstrap v0.33.1 h1:esGY+qXFJ78myppBzMVqqj37ReGLOJpQNslRiqmQGes=
|
||||
k8s.io/cluster-bootstrap v0.33.1/go.mod h1:YA4FsgPShsVoP84DkBJEkCKDgsH4PpgTa0NzNBf6y4I=
|
||||
k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
|
||||
k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
|
||||
k8s.io/component-helpers v0.33.1 h1:DdQMww8jOr+sGhIrkz70Lp9Qerq/JzeZDBRd508DHDo=
|
||||
k8s.io/component-helpers v0.33.1/go.mod h1:LQwxW5L3dH7341Unj+phndJu0Ic5UjxA//7FT8YVP5U=
|
||||
k8s.io/controller-manager v0.33.1 h1:ZYTzGp2f9TVhHCvrgSQtc367yR+D3UditkHDHCZc2GU=
|
||||
k8s.io/controller-manager v0.33.1/go.mod h1:p1yW7I5NFIuhXvSW9Wa/MdN3oIqXd2DRDgacb/hcUF0=
|
||||
k8s.io/cri-api v0.33.1 h1:CEvLiHZm/uTTp/5qsesU8/OG1a56RPnwMk4Ae73bUvs=
|
||||
k8s.io/cri-api v0.33.1/go.mod h1:OLQvT45OpIA+tv91ZrpuFIGY+Y2Ho23poS7n115Aocs=
|
||||
k8s.io/cri-client v0.33.1 h1:vf7mTWzoEevzn5djCroiFcSeh3SjPHQLYxf7MfKaD/s=
|
||||
k8s.io/cri-client v0.33.1/go.mod h1:bvAESUt8opvWLr8tzF4DG2GvZI9lSu6t9sCsqwJdpKE=
|
||||
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.33.0 h1:fhQSW/vyaWDhMp0vDuO/sLg2RlGZf4F77beSXcB4/eE=
|
||||
k8s.io/kms v0.33.0/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E=
|
||||
k8s.io/kms v0.33.1 h1:jJKrFhsbVofpyLF+G8k+drwOAF9CMQpxilHa5Uilb8Q=
|
||||
k8s.io/kms v0.33.1/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||
k8s.io/kube-proxy v0.33.0 h1:Sayf1JKu5toDhJeDYCNcucSyyqnHdMHU/JcFi5g2008=
|
||||
k8s.io/kube-proxy v0.33.0/go.mod h1:C0ZiTrHD2A3yL830p4/6bgUD2h5Mh5DfPwgL/JYXS3M=
|
||||
k8s.io/kubelet v0.33.0 h1:4pJA2Ge6Rp0kDNV76KH7pTBiaV2T1a1874QHMcubuSU=
|
||||
k8s.io/kubelet v0.33.0/go.mod h1:iDnxbJQMy9DUNaML5L/WUlt3uJtNLWh7ZAe0JSp4Yi0=
|
||||
k8s.io/kubernetes v1.33.0 h1:BP5Y5yIzUZVeBuE/ESZvnw6TNxjXbLsCckIkljE+R0U=
|
||||
k8s.io/kubernetes v1.33.0/go.mod h1:2nWuPk0seE4+6sd0x60wQ6rYEXcV7SoeMbU0YbFm/5k=
|
||||
k8s.io/kube-proxy v0.33.1 h1:mjUKwp7fSl/BFEjyPVCkFFN79P1BGdH9rzWFxYqW3V0=
|
||||
k8s.io/kube-proxy v0.33.1/go.mod h1:3JqyZuGGzo3TspjBERUpnuv9Bx9YvMyR4FgpCmrWiig=
|
||||
k8s.io/kubelet v0.33.1 h1:x4LCw1/iZVWOKA4RoITnuB8gMHnw31HPB3S0EF0EexE=
|
||||
k8s.io/kubelet v0.33.1/go.mod h1:8WpdC9M95VmsqIdGSQrajXooTfT5otEj8pGWOm+KKfQ=
|
||||
k8s.io/kubernetes v1.33.2 h1:Vk3hsCaazyMQ6CXhu029AEPlBoYsEnD8oEIC0bP2pWQ=
|
||||
k8s.io/kubernetes v1.33.2/go.mod h1:nrt8sldmckKz2fCZhgRX3SKfS2e+CzXATPv6ITNkU00=
|
||||
k8s.io/system-validators v1.9.1 h1:O8xrr08foamG+1uQjAdiTLt/fT+QQJ4QNREfCWvuOws=
|
||||
k8s.io/system-validators v1.9.1/go.mod h1:d4UVrxKu52s0BHU984Peb9VpIq4V9sd8xjTBV/waY/I=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||
@@ -527,8 +532,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.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
||||
sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU=
|
||||
sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY=
|
||||
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
|
||||
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package kubeadm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -46,6 +47,21 @@ func CreateKubeconfig(kubeconfigName string, ca CertificatePrivateKeyPair, confi
|
||||
return os.ReadFile(path)
|
||||
}
|
||||
|
||||
func IsKubeconfigCAValid(in, caCrt []byte) bool {
|
||||
kc, err := utilities.DecodeKubeconfigYAML(in)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, cluster := range kc.Clusters {
|
||||
if !bytes.Equal(cluster.Cluster.CertificateAuthorityData, caCrt) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func IsKubeconfigValid(bytes []byte) bool {
|
||||
kc, err := utilities.DecodeKubeconfigYAML(bytes)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
@@ -37,6 +38,12 @@ type CoreDNS struct {
|
||||
serviceAccount *corev1.ServiceAccount
|
||||
}
|
||||
|
||||
func (c *CoreDNS) GetHistogram() prometheus.Histogram {
|
||||
coreDNSCollector = resources.LazyLoadHistogramFromResource(coreDNSCollector, c)
|
||||
|
||||
return coreDNSCollector
|
||||
}
|
||||
|
||||
func (c *CoreDNS) Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
c.deployment = &appsv1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
@@ -39,6 +40,12 @@ type KubeProxy struct {
|
||||
daemonSet *appsv1.DaemonSet
|
||||
}
|
||||
|
||||
func (k *KubeProxy) GetHistogram() prometheus.Histogram {
|
||||
kubeProxyCollector = resources.LazyLoadHistogramFromResource(kubeProxyCollector, k)
|
||||
|
||||
return kubeProxyCollector
|
||||
}
|
||||
|
||||
func (k *KubeProxy) Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
k.clusterRoleBinding = &rbacv1.ClusterRoleBinding{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
13
internal/resources/addons/metrics.go
Normal file
13
internal/resources/addons/metrics.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package addons
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
kubeProxyCollector prometheus.Histogram
|
||||
coreDNSCollector prometheus.Histogram
|
||||
)
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
@@ -31,6 +32,12 @@ type APIServerCertificate struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *APIServerCertificate) GetHistogram() prometheus.Histogram {
|
||||
apiservercertificateCollector = LazyLoadHistogramFromResource(apiservercertificateCollector, r)
|
||||
|
||||
return apiservercertificateCollector
|
||||
}
|
||||
|
||||
func (r *APIServerCertificate) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Certificates.APIServer.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
@@ -110,7 +117,7 @@ func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *k
|
||||
r.resource.SetLabels(utilities.MergeMaps(
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "x509",
|
||||
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
||||
},
|
||||
))
|
||||
|
||||
@@ -120,7 +127,9 @@ func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *k
|
||||
return err
|
||||
}
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.APIServer.Checksum; len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0 {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.APIServer.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0) {
|
||||
isCAValid, err := crypto.VerifyCertificate(r.resource.Data[kubeadmconstants.APIServerCertName], secretCA.Data[kubeadmconstants.CACertName], x509.ExtKeyUsageServerAuth)
|
||||
if err != nil {
|
||||
logger.Info(fmt.Sprintf("certificate-authority verify failed: %s", err.Error()))
|
||||
@@ -163,6 +172,10 @@ func (r *APIServerCertificate) mutate(ctx context.Context, tenantControlPlane *k
|
||||
return err
|
||||
}
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
r.resource.Data = map[string][]byte{
|
||||
kubeadmconstants.APIServerCertName: certificateKeyPair.Certificate,
|
||||
kubeadmconstants.APIServerKeyName: certificateKeyPair.PrivateKey,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
@@ -30,6 +31,12 @@ type APIServerKubeletClientCertificate struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *APIServerKubeletClientCertificate) GetHistogram() prometheus.Histogram {
|
||||
clientcertificateCollector = LazyLoadHistogramFromResource(clientcertificateCollector, r)
|
||||
|
||||
return clientcertificateCollector
|
||||
}
|
||||
|
||||
func (r *APIServerKubeletClientCertificate) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Certificates.APIServerKubeletClient.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
@@ -97,7 +104,7 @@ func (r *APIServerKubeletClientCertificate) mutate(ctx context.Context, tenantCo
|
||||
r.resource.SetLabels(utilities.MergeMaps(
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "x509",
|
||||
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
||||
},
|
||||
))
|
||||
|
||||
@@ -107,7 +114,9 @@ func (r *APIServerKubeletClientCertificate) mutate(ctx context.Context, tenantCo
|
||||
return err
|
||||
}
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.APIServerKubeletClient.Checksum; len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0 {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.APIServerKubeletClient.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0) {
|
||||
isCAValid, err := crypto.VerifyCertificate(r.resource.Data[kubeadmconstants.APIServerKubeletClientCertName], secretCA.Data[kubeadmconstants.CACertName], x509.ExtKeyUsageClientAuth)
|
||||
if err != nil {
|
||||
logger.Info(fmt.Sprintf("certificate-authority verify failed: %s", err.Error()))
|
||||
@@ -145,6 +154,10 @@ func (r *APIServerKubeletClientCertificate) mutate(ctx context.Context, tenantCo
|
||||
return err
|
||||
}
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
r.resource.Data = map[string][]byte{
|
||||
kubeadmconstants.APIServerKubeletClientCertName: certificateKeyPair.Certificate,
|
||||
kubeadmconstants.APIServerKubeletClientKeyName: certificateKeyPair.PrivateKey,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
@@ -30,6 +31,12 @@ type CACertificate struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *CACertificate) GetHistogram() prometheus.Histogram {
|
||||
certificateauthorityCollector = LazyLoadHistogramFromResource(certificateauthorityCollector, r)
|
||||
|
||||
return certificateauthorityCollector
|
||||
}
|
||||
|
||||
func (r *CACertificate) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return r.isRotatingCA || tenantControlPlane.Status.Certificates.CA.SecretName != r.resource.GetName() ||
|
||||
tenantControlPlane.Status.Certificates.CA.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
@@ -89,7 +96,9 @@ func (r *CACertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1
|
||||
return func() error {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.CA.Checksum; len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0 {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.CA.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0) {
|
||||
isValid, err := crypto.CheckCertificateAndPrivateKeyPairValidity(
|
||||
r.resource.Data[kubeadmconstants.CACertName],
|
||||
r.resource.Data[kubeadmconstants.CAKeyName],
|
||||
@@ -109,6 +118,10 @@ func (r *CACertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1
|
||||
}
|
||||
}
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
if tenantControlPlane.Status.Kubernetes.Version.Status != nil && *tenantControlPlane.Status.Kubernetes.Version.Status != kamajiv1alpha1.VersionProvisioning {
|
||||
r.isRotatingCA = true
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/constants"
|
||||
"github.com/clastix/kamaji/internal/crypto"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -28,6 +30,12 @@ type Certificate struct {
|
||||
DataStore kamajiv1alpha1.DataStore
|
||||
}
|
||||
|
||||
func (r *Certificate) GetHistogram() prometheus.Histogram {
|
||||
certificateCollector = resources.LazyLoadHistogramFromResource(certificateCollector, r)
|
||||
|
||||
return certificateCollector
|
||||
}
|
||||
|
||||
func (r *Certificate) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Storage.Certificate.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
@@ -79,6 +87,8 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al
|
||||
return func() error {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if r.DataStore.Spec.TLSConfig != nil {
|
||||
ca, err := r.DataStore.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, r.Client)
|
||||
if err != nil {
|
||||
@@ -96,7 +106,7 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al
|
||||
r.resource.SetLabels(utilities.MergeMaps(
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "x509",
|
||||
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
||||
},
|
||||
))
|
||||
|
||||
@@ -108,7 +118,7 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al
|
||||
|
||||
if utilities.GetObjectChecksum(r.resource) == utilities.CalculateMapChecksum(r.resource.Data) {
|
||||
if r.DataStore.Spec.Driver == kamajiv1alpha1.EtcdDriver {
|
||||
if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"]); isValid {
|
||||
if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"]); isValid && !isRotationRequested {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -166,6 +176,10 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al
|
||||
r.resource.Data = map[string][]byte{}
|
||||
}
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
utilities.SetObjectChecksum(r.resource, r.resource.Data)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -6,7 +6,10 @@ package datastore
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -36,6 +39,12 @@ type Migrate struct {
|
||||
inProgress bool
|
||||
}
|
||||
|
||||
func (d *Migrate) GetHistogram() prometheus.Histogram {
|
||||
migrateCollector = resources.LazyLoadHistogramFromResource(migrateCollector, d)
|
||||
|
||||
return migrateCollector
|
||||
}
|
||||
|
||||
func (d *Migrate) Define(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
|
||||
if len(tenantControlPlane.Status.Storage.DataStoreName) == 0 {
|
||||
return nil
|
||||
@@ -115,9 +124,27 @@ func (d *Migrate) CreateOrUpdate(ctx context.Context, tenantControlPlane *kamaji
|
||||
fmt.Sprintf("--target-datastore=%s", tenantControlPlane.Spec.DataStore),
|
||||
}
|
||||
|
||||
if annotations := tenantControlPlane.GetAnnotations(); annotations != nil {
|
||||
v, _ := strconv.ParseBool(annotations["kamaji.clastix.io/cleanup-prior-migration"])
|
||||
d.job.Spec.Template.Spec.Containers[0].Args = append(d.job.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--cleanup-prior-migration=%t", v))
|
||||
|
||||
if timeout, tErr := time.ParseDuration(annotations["kamaji.clastix.io/migration-timeout"]); tErr == nil {
|
||||
d.job.Spec.Template.Spec.Containers[0].Args = append(d.job.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--timeout=%s", timeout.String()))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
// Jobs are immutable, except for a tiny subset of fields:
|
||||
// these are useless for Kamaji, and we don't have proper RBAC.
|
||||
// If the Job has a UUID, it means it's an update, and we're expecting that error.
|
||||
if errors.IsForbidden(err) && d.job.UID != "" {
|
||||
_ = d.Client.Delete(ctx, d.job)
|
||||
|
||||
return controllerutil.OperationResultNone, fmt.Errorf("migration job must be cretaed back due to immutable fields")
|
||||
}
|
||||
|
||||
return res, fmt.Errorf("unable to launch migrate job: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,29 +7,37 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
)
|
||||
|
||||
type MultiTenancy struct {
|
||||
DataStore kamajiv1alpha1.DataStore
|
||||
}
|
||||
|
||||
func (m MultiTenancy) Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
func (m *MultiTenancy) GetHistogram() prometheus.Histogram {
|
||||
multiTenancyCollector = resources.LazyLoadHistogramFromResource(multiTenancyCollector, m)
|
||||
|
||||
return multiTenancyCollector
|
||||
}
|
||||
|
||||
func (m *MultiTenancy) Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m MultiTenancy) ShouldCleanup(*kamajiv1alpha1.TenantControlPlane) bool {
|
||||
func (m *MultiTenancy) ShouldCleanup(*kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m MultiTenancy) CleanUp(context.Context, *kamajiv1alpha1.TenantControlPlane) (bool, error) {
|
||||
func (m *MultiTenancy) CleanUp(context.Context, *kamajiv1alpha1.TenantControlPlane) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (m MultiTenancy) CreateOrUpdate(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
|
||||
func (m *MultiTenancy) CreateOrUpdate(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
|
||||
// If the NATS Datastore is already used by a Tenant Control Plane
|
||||
// and a new one is reclaiming it, we need to stop it, since it's not allowed.
|
||||
// TODO(prometherion): remove this after multi-tenancy is implemented for NATS.
|
||||
@@ -49,14 +57,14 @@ func (m MultiTenancy) CreateOrUpdate(_ context.Context, tcp *kamajiv1alpha1.Tena
|
||||
}
|
||||
}
|
||||
|
||||
func (m MultiTenancy) GetName() string {
|
||||
func (m *MultiTenancy) GetName() string {
|
||||
return "ds.multitenancy"
|
||||
}
|
||||
|
||||
func (m MultiTenancy) ShouldStatusBeUpdated(context.Context, *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
func (m *MultiTenancy) ShouldStatusBeUpdated(context.Context, *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m MultiTenancy) UpdateTenantControlPlaneStatus(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
func (m *MultiTenancy) UpdateTenantControlPlaneStatus(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -18,6 +19,7 @@ import (
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/controllers/finalizers"
|
||||
"github.com/clastix/kamaji/internal/datastore"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/resources/utils"
|
||||
)
|
||||
|
||||
@@ -34,6 +36,12 @@ type Setup struct {
|
||||
DataStore kamajiv1alpha1.DataStore
|
||||
}
|
||||
|
||||
func (r *Setup) GetHistogram() prometheus.Histogram {
|
||||
setupCollector = resources.LazyLoadHistogramFromResource(setupCollector, r)
|
||||
|
||||
return setupCollector
|
||||
}
|
||||
|
||||
func (r *Setup) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Storage.Driver != string(r.DataStore.Spec.Driver) ||
|
||||
tenantControlPlane.Status.Storage.Setup.Checksum != tenantControlPlane.Status.Storage.Config.Checksum ||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kubeerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/controllers/finalizers"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -32,6 +34,12 @@ type Config struct {
|
||||
DataStore kamajiv1alpha1.DataStore
|
||||
}
|
||||
|
||||
func (r *Config) GetHistogram() prometheus.Histogram {
|
||||
storageCollector = resources.LazyLoadHistogramFromResource(storageCollector, r)
|
||||
|
||||
return storageCollector
|
||||
}
|
||||
|
||||
func (r *Config) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Storage.Config.Checksum != utilities.GetObjectChecksum(r.resource) ||
|
||||
tenantControlPlane.Status.Storage.DataStoreName != r.DataStore.GetName()
|
||||
|
||||
16
internal/resources/datastore/metrics.go
Normal file
16
internal/resources/datastore/metrics.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
certificateCollector prometheus.Histogram
|
||||
migrateCollector prometheus.Histogram
|
||||
multiTenancyCollector prometheus.Histogram
|
||||
setupCollector prometheus.Histogram
|
||||
storageCollector prometheus.Histogram
|
||||
)
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
@@ -30,6 +31,12 @@ type FrontProxyClientCertificate struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *FrontProxyClientCertificate) GetHistogram() prometheus.Histogram {
|
||||
frontproxycertificateCollector = LazyLoadHistogramFromResource(frontproxycertificateCollector, r)
|
||||
|
||||
return frontproxycertificateCollector
|
||||
}
|
||||
|
||||
func (r *FrontProxyClientCertificate) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Certificates.FrontProxyClient.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
@@ -97,7 +104,7 @@ func (r *FrontProxyClientCertificate) mutate(ctx context.Context, tenantControlP
|
||||
r.resource.SetLabels(utilities.MergeMaps(
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "x509",
|
||||
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
||||
},
|
||||
))
|
||||
|
||||
@@ -107,7 +114,9 @@ func (r *FrontProxyClientCertificate) mutate(ctx context.Context, tenantControlP
|
||||
return err
|
||||
}
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.FrontProxyClient.Checksum; len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0 {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.FrontProxyClient.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0) {
|
||||
isCAValid, err := crypto.VerifyCertificate(r.resource.Data[kubeadmconstants.FrontProxyClientCertName], secretCA.Data[kubeadmconstants.FrontProxyCACertName], x509.ExtKeyUsageClientAuth)
|
||||
if err != nil {
|
||||
logger.Info(fmt.Sprintf("certificate-authority verify failed: %s", err.Error()))
|
||||
@@ -145,6 +154,10 @@ func (r *FrontProxyClientCertificate) mutate(ctx context.Context, tenantControlP
|
||||
return err
|
||||
}
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
r.resource.Data = map[string][]byte{
|
||||
kubeadmconstants.FrontProxyClientCertName: certificateKeyPair.Certificate,
|
||||
kubeadmconstants.FrontProxyClientKeyName: certificateKeyPair.PrivateKey,
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
@@ -27,6 +28,12 @@ type FrontProxyCACertificate struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *FrontProxyCACertificate) GetHistogram() prometheus.Histogram {
|
||||
frontproxycaCollector = LazyLoadHistogramFromResource(frontproxycaCollector, r)
|
||||
|
||||
return frontproxycaCollector
|
||||
}
|
||||
|
||||
func (r *FrontProxyCACertificate) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Certificates.FrontProxyCA.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
@@ -82,7 +89,9 @@ func (r *FrontProxyCACertificate) mutate(ctx context.Context, tenantControlPlane
|
||||
return func() error {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.FrontProxyCA.Checksum; len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0 {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.FrontProxyCA.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0) {
|
||||
isValid, err := crypto.CheckCertificateAndPrivateKeyPairValidity(
|
||||
r.resource.Data[kubeadmconstants.FrontProxyCACertName],
|
||||
r.resource.Data[kubeadmconstants.FrontProxyCAKeyName],
|
||||
@@ -116,6 +125,10 @@ func (r *FrontProxyCACertificate) mutate(ctx context.Context, tenantControlPlane
|
||||
|
||||
r.resource.SetLabels(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()))
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
utilities.SetObjectChecksum(r.resource, r.resource.Data)
|
||||
|
||||
return ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme())
|
||||
|
||||
@@ -6,6 +6,7 @@ package resources
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/utils/ptr"
|
||||
@@ -21,10 +22,15 @@ type KubernetesDeploymentResource struct {
|
||||
resource *appsv1.Deployment
|
||||
Client client.Client
|
||||
DataStore kamajiv1alpha1.DataStore
|
||||
Name string
|
||||
KineContainerImage string
|
||||
}
|
||||
|
||||
func (r *KubernetesDeploymentResource) GetHistogram() prometheus.Histogram {
|
||||
deploymentCollector = LazyLoadHistogramFromResource(deploymentCollector, r)
|
||||
|
||||
return deploymentCollector
|
||||
}
|
||||
|
||||
func (r *KubernetesDeploymentResource) isStatusEqual(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return r.resource.Status.String() == tenantControlPlane.Status.Kubernetes.Deployment.DeploymentStatus.String()
|
||||
}
|
||||
@@ -49,8 +55,6 @@ func (r *KubernetesDeploymentResource) Define(_ context.Context, tenantControlPl
|
||||
},
|
||||
}
|
||||
|
||||
r.Name = "deployment"
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -71,7 +75,7 @@ func (r *KubernetesDeploymentResource) CreateOrUpdate(ctx context.Context, tenan
|
||||
}
|
||||
|
||||
func (r *KubernetesDeploymentResource) GetName() string {
|
||||
return r.Name
|
||||
return "deployment"
|
||||
}
|
||||
|
||||
func (r *KubernetesDeploymentResource) UpdateTenantControlPlaneStatus(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -22,7 +23,12 @@ import (
|
||||
type KubernetesIngressResource struct {
|
||||
resource *networkingv1.Ingress
|
||||
Client client.Client
|
||||
Name string
|
||||
}
|
||||
|
||||
func (r *KubernetesIngressResource) GetHistogram() prometheus.Histogram {
|
||||
ingressCollector = LazyLoadHistogramFromResource(ingressCollector, r)
|
||||
|
||||
return ingressCollector
|
||||
}
|
||||
|
||||
func (r *KubernetesIngressResource) ShouldStatusBeUpdated(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
@@ -140,8 +146,6 @@ func (r *KubernetesIngressResource) Define(_ context.Context, tenantControlPlane
|
||||
},
|
||||
}
|
||||
|
||||
r.Name = "ingress"
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -211,5 +215,5 @@ func (r *KubernetesIngressResource) CreateOrUpdate(ctx context.Context, tenantCo
|
||||
}
|
||||
|
||||
func (r *KubernetesIngressResource) GetName() string {
|
||||
return r.Name
|
||||
return "ingress"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
@@ -26,6 +27,12 @@ type KubernetesServiceResource struct {
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
func (r *KubernetesServiceResource) GetHistogram() prometheus.Histogram {
|
||||
serviceCollector = LazyLoadHistogramFromResource(serviceCollector, r)
|
||||
|
||||
return serviceCollector
|
||||
}
|
||||
|
||||
func (r *KubernetesServiceResource) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Kubernetes.Service.Name != r.resource.GetName() ||
|
||||
tenantControlPlane.Status.Kubernetes.Service.Namespace != r.resource.GetNamespace() ||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -19,18 +20,26 @@ import (
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/constants"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
type Agent struct {
|
||||
resource *appsv1.DaemonSet
|
||||
resource client.Object
|
||||
Client client.Client
|
||||
tenantClient client.Client
|
||||
}
|
||||
|
||||
func (r *Agent) GetHistogram() prometheus.Histogram {
|
||||
agentCollector = resources.LazyLoadHistogramFromResource(agentCollector, r)
|
||||
|
||||
return agentCollector
|
||||
}
|
||||
|
||||
func (r *Agent) ShouldStatusBeUpdated(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tcp.Spec.Addons.Konnectivity == nil && (tcp.Status.Addons.Konnectivity.Agent.Namespace != "" || tcp.Status.Addons.Konnectivity.Agent.Name != "") ||
|
||||
tcp.Spec.Addons.Konnectivity != nil && (tcp.Status.Addons.Konnectivity.Agent.Namespace != r.resource.Namespace || tcp.Status.Addons.Konnectivity.Agent.Name != r.resource.Name)
|
||||
tcp.Spec.Addons.Konnectivity != nil && (tcp.Status.Addons.Konnectivity.Agent.Namespace != r.resource.GetNamespace() || tcp.Status.Addons.Konnectivity.Agent.Name != r.resource.GetName()) ||
|
||||
tcp.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Mode != tcp.Status.Addons.Konnectivity.Agent.Mode
|
||||
}
|
||||
|
||||
func (r *Agent) ShouldCleanup(tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
@@ -70,13 +79,20 @@ func (r *Agent) CleanUp(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlan
|
||||
func (r *Agent) Define(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (err error) {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
|
||||
r.resource = &appsv1.DaemonSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: AgentName,
|
||||
Namespace: AgentNamespace,
|
||||
},
|
||||
switch tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Mode {
|
||||
case kamajiv1alpha1.KonnectivityAgentModeDaemonSet:
|
||||
r.resource = &appsv1.DaemonSet{}
|
||||
case kamajiv1alpha1.KonnectivityAgentModeDeployment:
|
||||
r.resource = &appsv1.Deployment{}
|
||||
default:
|
||||
logger.Info("TenantControlPlane CRD is not updated, or validation failed, fallback to DaemonSet")
|
||||
|
||||
r.resource = &appsv1.DaemonSet{}
|
||||
}
|
||||
|
||||
r.resource.SetNamespace(AgentNamespace)
|
||||
r.resource.SetName(AgentName)
|
||||
|
||||
if r.tenantClient, err = utilities.GetTenantClient(ctx, r.Client, tenantControlPlane); err != nil {
|
||||
logger.Error(err, "unable to retrieve the Tenant Control Plane client")
|
||||
|
||||
@@ -88,7 +104,33 @@ func (r *Agent) Define(ctx context.Context, tenantControlPlane *kamajiv1alpha1.T
|
||||
|
||||
func (r *Agent) CreateOrUpdate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
|
||||
if tenantControlPlane.Spec.Addons.Konnectivity != nil {
|
||||
return controllerutil.CreateOrUpdate(ctx, r.tenantClient, r.resource, r.mutate(ctx, tenantControlPlane))
|
||||
or, err := controllerutil.CreateOrUpdate(ctx, r.tenantClient, r.resource, r.mutate(ctx, tenantControlPlane))
|
||||
if err != nil {
|
||||
return controllerutil.OperationResultNone, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Mode == kamajiv1alpha1.KonnectivityAgentModeDaemonSet &&
|
||||
tenantControlPlane.Status.Addons.Konnectivity.Agent.Mode != kamajiv1alpha1.KonnectivityAgentModeDaemonSet:
|
||||
var obj appsv1.Deployment
|
||||
obj.SetName(r.resource.GetName())
|
||||
obj.SetNamespace(r.resource.GetNamespace())
|
||||
|
||||
if cleanupErr := r.tenantClient.Delete(ctx, &obj); cleanupErr != nil {
|
||||
log.FromContext(ctx, "resource", r.GetName()).Error(cleanupErr, "cannot cleanup older appsv1.Deployment")
|
||||
}
|
||||
case tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Mode == kamajiv1alpha1.KonnectivityAgentModeDeployment &&
|
||||
tenantControlPlane.Status.Addons.Konnectivity.Agent.Mode != kamajiv1alpha1.KonnectivityAgentModeDeployment:
|
||||
var obj appsv1.DaemonSet
|
||||
obj.SetName(r.resource.GetName())
|
||||
obj.SetNamespace(r.resource.GetNamespace())
|
||||
|
||||
if cleanupErr := r.tenantClient.Delete(ctx, &obj); cleanupErr != nil {
|
||||
log.FromContext(ctx, "resource", r.GetName()).Error(cleanupErr, "cannot cleanup older appsv1.DaemonSet")
|
||||
}
|
||||
}
|
||||
|
||||
return or, nil
|
||||
}
|
||||
|
||||
return controllerutil.OperationResultNone, nil
|
||||
@@ -99,13 +141,16 @@ func (r *Agent) GetName() string {
|
||||
}
|
||||
|
||||
func (r *Agent) UpdateTenantControlPlaneStatus(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
|
||||
tenantControlPlane.Status.Addons.Konnectivity.Agent = kamajiv1alpha1.ExternalKubernetesObjectStatus{}
|
||||
tenantControlPlane.Status.Addons.Konnectivity.Agent = kamajiv1alpha1.KonnectivityAgentStatus{}
|
||||
|
||||
if tenantControlPlane.Spec.Addons.Konnectivity != nil {
|
||||
tenantControlPlane.Status.Addons.Konnectivity.Agent = kamajiv1alpha1.ExternalKubernetesObjectStatus{
|
||||
Name: r.resource.GetName(),
|
||||
Namespace: r.resource.GetNamespace(),
|
||||
LastUpdate: metav1.Now(),
|
||||
tenantControlPlane.Status.Addons.Konnectivity.Agent = kamajiv1alpha1.KonnectivityAgentStatus{
|
||||
ExternalKubernetesObjectStatus: kamajiv1alpha1.ExternalKubernetesObjectStatus{
|
||||
Name: r.resource.GetName(),
|
||||
Namespace: r.resource.GetNamespace(),
|
||||
LastUpdate: metav1.Now(),
|
||||
},
|
||||
Mode: tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Mode,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,27 +170,31 @@ func (r *Agent) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.T
|
||||
|
||||
r.resource.SetLabels(utilities.MergeMaps(r.resource.GetLabels(), utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName())))
|
||||
|
||||
if r.resource.Spec.Selector == nil {
|
||||
r.resource.Spec.Selector = &metav1.LabelSelector{}
|
||||
}
|
||||
r.resource.Spec.Selector.MatchLabels = map[string]string{
|
||||
"k8s-app": AgentName,
|
||||
}
|
||||
|
||||
r.resource.Spec.Template.SetLabels(utilities.MergeMaps(
|
||||
r.resource.Spec.Template.GetLabels(),
|
||||
map[string]string{
|
||||
specSelector := &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"k8s-app": AgentName,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
r.resource.Spec.Template.Spec.PriorityClassName = "system-cluster-critical"
|
||||
r.resource.Spec.Template.Spec.Tolerations = tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Tolerations
|
||||
r.resource.Spec.Template.Spec.NodeSelector = map[string]string{
|
||||
var podTemplateSpec *corev1.PodTemplateSpec
|
||||
|
||||
switch obj := r.resource.(type) {
|
||||
case *appsv1.DaemonSet:
|
||||
obj.Spec.Selector = specSelector
|
||||
podTemplateSpec = &obj.Spec.Template
|
||||
case *appsv1.Deployment:
|
||||
obj.Spec.Selector = specSelector
|
||||
podTemplateSpec = &obj.Spec.Template
|
||||
}
|
||||
|
||||
podTemplateSpec.SetLabels(utilities.MergeMaps(podTemplateSpec.GetLabels(), specSelector.MatchLabels))
|
||||
podTemplateSpec.Spec.PriorityClassName = "system-cluster-critical"
|
||||
podTemplateSpec.Spec.Tolerations = tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Tolerations
|
||||
podTemplateSpec.Spec.NodeSelector = map[string]string{
|
||||
"kubernetes.io/os": "linux",
|
||||
}
|
||||
r.resource.Spec.Template.Spec.ServiceAccountName = AgentName
|
||||
r.resource.Spec.Template.Spec.Volumes = []corev1.Volume{
|
||||
podTemplateSpec.Spec.ServiceAccountName = AgentName
|
||||
podTemplateSpec.Spec.Volumes = []corev1.Volume{
|
||||
{
|
||||
Name: agentTokenName,
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
@@ -165,13 +214,13 @@ func (r *Agent) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.T
|
||||
},
|
||||
}
|
||||
|
||||
if len(r.resource.Spec.Template.Spec.Containers) != 1 {
|
||||
r.resource.Spec.Template.Spec.Containers = make([]corev1.Container, 1)
|
||||
if len(podTemplateSpec.Spec.Containers) != 1 {
|
||||
podTemplateSpec.Spec.Containers = make([]corev1.Container, 1)
|
||||
}
|
||||
|
||||
r.resource.Spec.Template.Spec.Containers[0].Image = fmt.Sprintf("%s:%s", tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Image, tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Version)
|
||||
r.resource.Spec.Template.Spec.Containers[0].Name = AgentName
|
||||
r.resource.Spec.Template.Spec.Containers[0].Command = []string{"/proxy-agent"}
|
||||
podTemplateSpec.Spec.Containers[0].Image = fmt.Sprintf("%s:%s", tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Image, tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Version)
|
||||
podTemplateSpec.Spec.Containers[0].Name = AgentName
|
||||
podTemplateSpec.Spec.Containers[0].Command = []string{"/proxy-agent"}
|
||||
|
||||
args := make(map[string]string)
|
||||
args["-v"] = "8"
|
||||
@@ -189,18 +238,18 @@ func (r *Agent) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.T
|
||||
args[k] = v
|
||||
}
|
||||
|
||||
r.resource.Spec.Template.Spec.Containers[0].Args = utilities.ArgsFromMapToSlice(args)
|
||||
r.resource.Spec.Template.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
|
||||
podTemplateSpec.Spec.Containers[0].Args = utilities.ArgsFromMapToSlice(args)
|
||||
podTemplateSpec.Spec.Containers[0].VolumeMounts = []corev1.VolumeMount{
|
||||
{
|
||||
MountPath: "/var/run/secrets/tokens",
|
||||
Name: agentTokenName,
|
||||
},
|
||||
}
|
||||
r.resource.Spec.Template.Spec.Containers[0].LivenessProbe = &corev1.Probe{
|
||||
podTemplateSpec.Spec.Containers[0].LivenessProbe = &corev1.Probe{
|
||||
ProbeHandler: corev1.ProbeHandler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
Path: "/healthz",
|
||||
Port: intstr.FromInt(8134),
|
||||
Port: intstr.FromInt32(8134),
|
||||
Scheme: corev1.URISchemeHTTP,
|
||||
},
|
||||
},
|
||||
@@ -211,6 +260,16 @@ func (r *Agent) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.T
|
||||
FailureThreshold: 3,
|
||||
}
|
||||
|
||||
switch tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Mode {
|
||||
case kamajiv1alpha1.KonnectivityAgentModeDaemonSet:
|
||||
r.resource.(*appsv1.DaemonSet).Spec.Template = *podTemplateSpec //nolint:forcetypeassert
|
||||
case kamajiv1alpha1.KonnectivityAgentModeDeployment:
|
||||
//nolint:forcetypeassert
|
||||
r.resource.(*appsv1.Deployment).Spec.Template = *podTemplateSpec
|
||||
//nolint:forcetypeassert
|
||||
r.resource.(*appsv1.Deployment).Spec.Replicas = pointer.To(tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Replicas)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
"github.com/clastix/kamaji/internal/constants"
|
||||
"github.com/clastix/kamaji/internal/crypto"
|
||||
"github.com/clastix/kamaji/internal/kubeadm"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -29,6 +31,12 @@ type CertificateResource struct {
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
func (r *CertificateResource) GetHistogram() prometheus.Histogram {
|
||||
certificateCollector = resources.LazyLoadHistogramFromResource(certificateCollector, r)
|
||||
|
||||
return certificateCollector
|
||||
}
|
||||
|
||||
func (r *CertificateResource) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Addons.Konnectivity.Certificate.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
@@ -96,7 +104,7 @@ func (r *CertificateResource) mutate(ctx context.Context, tenantControlPlane *ka
|
||||
r.resource.GetLabels(),
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "x509",
|
||||
constants.ControllerLabelResource: utilities.CertificateX509Label,
|
||||
},
|
||||
))
|
||||
|
||||
@@ -106,7 +114,9 @@ func (r *CertificateResource) mutate(ctx context.Context, tenantControlPlane *ka
|
||||
return err
|
||||
}
|
||||
|
||||
if checksum := tenantControlPlane.Status.Addons.Konnectivity.Certificate.Checksum; len(checksum) > 0 && checksum == utilities.CalculateMapChecksum(r.resource.Data) {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if checksum := tenantControlPlane.Status.Addons.Konnectivity.Certificate.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.CalculateMapChecksum(r.resource.Data)) {
|
||||
isValid, err := crypto.IsValidCertificateKeyPairBytes(r.resource.Data[corev1.TLSCertKey], r.resource.Data[corev1.TLSPrivateKeyKey])
|
||||
if err != nil {
|
||||
logger.Info(fmt.Sprintf("%s certificate-private_key pair is not valid: %s", konnectivityCertAndKeyBaseName, err.Error()))
|
||||
@@ -137,6 +147,10 @@ func (r *CertificateResource) mutate(ctx context.Context, tenantControlPlane *ka
|
||||
return err
|
||||
}
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
r.resource.Type = corev1.SecretTypeTLS
|
||||
r.resource.Data = map[string][]byte{
|
||||
corev1.TLSCertKey: cert.Bytes(),
|
||||
|
||||
@@ -6,6 +6,7 @@ package konnectivity
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/constants"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -25,6 +27,12 @@ type ClusterRoleBindingResource struct {
|
||||
tenantClient client.Client
|
||||
}
|
||||
|
||||
func (r *ClusterRoleBindingResource) GetHistogram() prometheus.Histogram {
|
||||
clusterrolebindingCollector = resources.LazyLoadHistogramFromResource(clusterrolebindingCollector, r)
|
||||
|
||||
return clusterrolebindingCollector
|
||||
}
|
||||
|
||||
func (r *ClusterRoleBindingResource) ShouldStatusBeUpdated(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tcp.Spec.Addons.Konnectivity == nil && tcp.Status.Addons.Konnectivity.ClusterRoleBinding.Name != "" ||
|
||||
tcp.Spec.Addons.Konnectivity != nil && (tcp.Status.Addons.Konnectivity.ClusterRoleBinding.Name == "" ||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
builder "github.com/clastix/kamaji/internal/builders/controlplane"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -25,6 +27,12 @@ type KubernetesDeploymentResource struct {
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
func (r *KubernetesDeploymentResource) GetHistogram() prometheus.Histogram {
|
||||
deploymentCollector = resources.LazyLoadHistogramFromResource(deploymentCollector, r)
|
||||
|
||||
return deploymentCollector
|
||||
}
|
||||
|
||||
func (r *KubernetesDeploymentResource) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
switch {
|
||||
case tenantControlPlane.Spec.Addons.Konnectivity == nil && tenantControlPlane.Status.Addons.Konnectivity.Enabled,
|
||||
|
||||
@@ -6,6 +6,7 @@ package konnectivity
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -24,6 +26,12 @@ type EgressSelectorConfigurationResource struct {
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
func (r *EgressSelectorConfigurationResource) GetHistogram() prometheus.Histogram {
|
||||
egressCollector = resources.LazyLoadHistogramFromResource(egressCollector, r)
|
||||
|
||||
return egressCollector
|
||||
}
|
||||
|
||||
func (r *EgressSelectorConfigurationResource) Define(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
|
||||
r.resource = &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/constants"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -28,6 +30,12 @@ type KubeconfigResource struct {
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
func (r *KubeconfigResource) GetHistogram() prometheus.Histogram {
|
||||
kubeconfigCollector = resources.LazyLoadHistogramFromResource(kubeconfigCollector, r)
|
||||
|
||||
return kubeconfigCollector
|
||||
}
|
||||
|
||||
func (r *KubeconfigResource) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Addons.Konnectivity.Kubeconfig.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
@@ -95,7 +103,7 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam
|
||||
r.resource.GetLabels(),
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "kubeconfig",
|
||||
constants.ControllerLabelResource: utilities.CertificateKubeconfigLabel,
|
||||
},
|
||||
))
|
||||
|
||||
@@ -105,7 +113,10 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam
|
||||
return err
|
||||
}
|
||||
|
||||
if checksum := tenantControlPlane.Status.Addons.Konnectivity.Certificate.Checksum; len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
checksum := tenantControlPlane.Status.Addons.Konnectivity.Kubeconfig.Checksum
|
||||
if len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) && !isRotationRequested {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -173,6 +184,8 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam
|
||||
konnectivityKubeconfigFileName: kubeconfigBytes,
|
||||
}
|
||||
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
|
||||
utilities.SetObjectChecksum(r.resource, r.resource.Data)
|
||||
|
||||
return nil
|
||||
|
||||
19
internal/resources/konnectivity/metrics.go
Normal file
19
internal/resources/konnectivity/metrics.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package konnectivity
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
agentCollector prometheus.Histogram
|
||||
certificateCollector prometheus.Histogram
|
||||
clusterrolebindingCollector prometheus.Histogram
|
||||
deploymentCollector prometheus.Histogram
|
||||
egressCollector prometheus.Histogram
|
||||
kubeconfigCollector prometheus.Histogram
|
||||
serviceaccountCollector prometheus.Histogram
|
||||
serviceCollector prometheus.Histogram
|
||||
)
|
||||
@@ -6,6 +6,7 @@ package konnectivity
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/constants"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -25,6 +27,12 @@ type ServiceAccountResource struct {
|
||||
tenantClient client.Client
|
||||
}
|
||||
|
||||
func (r *ServiceAccountResource) GetHistogram() prometheus.Histogram {
|
||||
serviceaccountCollector = resources.LazyLoadHistogramFromResource(serviceaccountCollector, r)
|
||||
|
||||
return serviceaccountCollector
|
||||
}
|
||||
|
||||
func (r *ServiceAccountResource) ShouldStatusBeUpdated(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tcp.Spec.Addons.Konnectivity == nil && len(tcp.Status.Addons.Konnectivity.ServiceAccount.Name) > 0 && len(tcp.Status.Addons.Konnectivity.ServiceAccount.Namespace) > 0 ||
|
||||
tcp.Spec.Addons.Konnectivity != nil && tcp.Status.Addons.Konnectivity.ServiceAccount.Name == "" && tcp.Status.Addons.Konnectivity.ServiceAccount.Namespace == ""
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/resources"
|
||||
"github.com/clastix/kamaji/internal/utilities"
|
||||
)
|
||||
|
||||
@@ -23,6 +25,12 @@ type ServiceResource struct {
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
func (r *ServiceResource) GetHistogram() prometheus.Histogram {
|
||||
serviceCollector = resources.LazyLoadHistogramFromResource(serviceCollector, r)
|
||||
|
||||
return serviceCollector
|
||||
}
|
||||
|
||||
func (r *ServiceResource) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
if tenantControlPlane.Spec.Addons.Konnectivity == nil &&
|
||||
tenantControlPlane.Status.Addons.Konnectivity.Service.Port == 0 &&
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
@@ -27,6 +28,12 @@ type KubeadmConfigResource struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *KubeadmConfigResource) GetHistogram() prometheus.Histogram {
|
||||
kubeadmconfigCollector = LazyLoadHistogramFromResource(kubeadmconfigCollector, r)
|
||||
|
||||
return kubeadmconfigCollector
|
||||
}
|
||||
|
||||
func (r *KubeadmConfigResource) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.KubeadmConfig.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -45,6 +46,29 @@ type KubeadmPhase struct {
|
||||
checksum string
|
||||
}
|
||||
|
||||
func (r *KubeadmPhase) GetHistogram() prometheus.Histogram {
|
||||
switch r.Phase {
|
||||
case PhaseUploadConfigKubeadm:
|
||||
kubeadmphaseUploadConfigKubeadmCollector = LazyLoadHistogramFromResource(kubeadmphaseUploadConfigKubeadmCollector, r)
|
||||
|
||||
return kubeadmphaseUploadConfigKubeadmCollector
|
||||
case PhaseUploadConfigKubelet:
|
||||
kubeadmphaseUploadConfigKubeletCollector = LazyLoadHistogramFromResource(kubeadmphaseUploadConfigKubeletCollector, r)
|
||||
|
||||
return kubeadmphaseUploadConfigKubeletCollector
|
||||
case PhaseBootstrapToken:
|
||||
kubeadmphaseBootstrapTokenCollector = LazyLoadHistogramFromResource(kubeadmphaseBootstrapTokenCollector, r)
|
||||
|
||||
return kubeadmphaseBootstrapTokenCollector
|
||||
case PhaseClusterAdminRBAC:
|
||||
kubeadmphaseClusterAdminRBACCollector = LazyLoadHistogramFromResource(kubeadmphaseClusterAdminRBACCollector, r)
|
||||
|
||||
return kubeadmphaseClusterAdminRBACCollector
|
||||
default:
|
||||
panic("should not happen")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *KubeadmPhase) GetWatchedObject() client.Object {
|
||||
switch r.Phase {
|
||||
case PhaseUploadConfigKubeadm:
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/phases/upgrade"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -26,6 +27,12 @@ type KubernetesUpgrade struct {
|
||||
inProgress bool
|
||||
}
|
||||
|
||||
func (k *KubernetesUpgrade) GetHistogram() prometheus.Histogram {
|
||||
kubeadmupgradeCollector = LazyLoadHistogramFromResource(kubeadmupgradeCollector, k)
|
||||
|
||||
return kubeadmupgradeCollector
|
||||
}
|
||||
|
||||
func (k *KubernetesUpgrade) Define(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
|
||||
k.upgrade = upgrade.Upgrade{
|
||||
Before: upgrade.ClusterState{
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
@@ -39,6 +40,12 @@ type KubeconfigResource struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *KubeconfigResource) GetHistogram() prometheus.Histogram {
|
||||
kubeconfigCollector = LazyLoadHistogramFromResource(kubeconfigCollector, r)
|
||||
|
||||
return kubeconfigCollector
|
||||
}
|
||||
|
||||
func (r *KubeconfigResource) ShouldStatusBeUpdated(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
// an update is required only in case of missing status checksum, or name:
|
||||
// this data is required by the following resource handlers.
|
||||
@@ -165,10 +172,10 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam
|
||||
r.resource.SetLabels(utilities.MergeMaps(
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "kubeconfig",
|
||||
constants.ControllerLabelResource: utilities.CertificateKubeconfigLabel,
|
||||
},
|
||||
))
|
||||
r.resource.SetAnnotations(map[string]string{constants.Checksum: checksum})
|
||||
r.resource.SetAnnotations(utilities.MergeMaps(r.resource.GetAnnotations(), map[string]string{constants.Checksum: checksum}))
|
||||
|
||||
if err = ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme()); err != nil {
|
||||
logger.Error(err, "cannot set controller reference", "resource", r.GetName())
|
||||
@@ -178,18 +185,21 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam
|
||||
|
||||
var shouldCreate bool
|
||||
|
||||
shouldCreate = shouldCreate || r.resource.Data == nil // Missing data key
|
||||
shouldCreate = shouldCreate || len(r.resource.Data) == 0 // Missing data key
|
||||
shouldCreate = shouldCreate || len(r.resource.Data[r.KubeConfigFileName]) == 0 // Missing kubeconfig file, must be generated
|
||||
shouldCreate = shouldCreate || r.resource.Data == nil // Missing data key
|
||||
shouldCreate = shouldCreate || len(r.resource.Data) == 0 // Missing data key
|
||||
shouldCreate = shouldCreate || len(r.resource.Data[r.KubeConfigFileName]) == 0 // Missing kubeconfig file, must be generated
|
||||
shouldCreate = shouldCreate || !kubeadm.IsKubeconfigCAValid(r.resource.Data[r.KubeConfigFileName], caCertificatesSecret.Data[kubeadmconstants.CACertName])
|
||||
shouldCreate = shouldCreate || !kubeadm.IsKubeconfigValid(r.resource.Data[r.KubeConfigFileName]) // invalid kubeconfig, or expired client certificate
|
||||
shouldCreate = shouldCreate || status.Checksum != checksum || len(r.resource.UID) == 0 // Wrong checksum
|
||||
|
||||
shouldRotate := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if !shouldCreate {
|
||||
v, ok := r.resource.Data[r.KubeConfigFileName]
|
||||
shouldCreate = len(v) == 0 || !ok
|
||||
}
|
||||
//nolint:nestif
|
||||
if shouldCreate {
|
||||
|
||||
if shouldCreate || shouldRotate {
|
||||
crtKeyPair := kubeadm.CertificatePrivateKeyPair{
|
||||
Certificate: caCertificatesSecret.Data[kubeadmconstants.CACertName],
|
||||
PrivateKey: caCertificatesSecret.Data[kubeadmconstants.CAKeyName],
|
||||
@@ -206,6 +216,10 @@ func (r *KubeconfigResource) mutate(ctx context.Context, tenantControlPlane *kam
|
||||
return kcErr
|
||||
}
|
||||
|
||||
if shouldRotate {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
r.resource.Data[r.KubeConfigFileName] = kubeconfig
|
||||
// Adding a kubeconfig useful for the local connections:
|
||||
// especially for the admin.conf and super-admin.conf, these would use the public IP address.
|
||||
|
||||
52
internal/resources/metrics.go
Normal file
52
internal/resources/metrics.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package resources
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
apiservercertificateCollector prometheus.Histogram
|
||||
clientcertificateCollector prometheus.Histogram
|
||||
certificateauthorityCollector prometheus.Histogram
|
||||
frontproxycertificateCollector prometheus.Histogram
|
||||
frontproxycaCollector prometheus.Histogram
|
||||
deploymentCollector prometheus.Histogram
|
||||
ingressCollector prometheus.Histogram
|
||||
serviceCollector prometheus.Histogram
|
||||
kubeadmconfigCollector prometheus.Histogram
|
||||
kubeadmupgradeCollector prometheus.Histogram
|
||||
kubeconfigCollector prometheus.Histogram
|
||||
serviceaccountcertificateCollector prometheus.Histogram
|
||||
|
||||
kubeadmphaseUploadConfigKubeadmCollector prometheus.Histogram
|
||||
kubeadmphaseUploadConfigKubeletCollector prometheus.Histogram
|
||||
kubeadmphaseBootstrapTokenCollector prometheus.Histogram
|
||||
kubeadmphaseClusterAdminRBACCollector prometheus.Histogram
|
||||
)
|
||||
|
||||
func LazyLoadHistogramFromResource(collector prometheus.Histogram, resource Resource) prometheus.Histogram {
|
||||
n := resource.GetName()
|
||||
|
||||
if collector == nil {
|
||||
c := prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||
Namespace: "kamaji",
|
||||
Subsystem: "handler",
|
||||
Name: n + "_time_seconds",
|
||||
Help: "Bucket time requested for the given handler to complete its handling.",
|
||||
Buckets: []float64{
|
||||
0.005, 0.01, 0.025, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
|
||||
1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 60,
|
||||
},
|
||||
})
|
||||
|
||||
metrics.Registry.MustRegister(c)
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
return collector
|
||||
}
|
||||
@@ -5,7 +5,9 @@ package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
@@ -20,7 +22,13 @@ const (
|
||||
OperationResultEnqueueBack controllerutil.OperationResult = "enqueueBack"
|
||||
)
|
||||
|
||||
type ResourceMetric interface {
|
||||
GetHistogram() prometheus.Histogram
|
||||
}
|
||||
|
||||
type Resource interface {
|
||||
ResourceMetric
|
||||
|
||||
Define(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) error
|
||||
ShouldCleanup(tcp *kamajiv1alpha1.TenantControlPlane) bool
|
||||
CleanUp(ctx context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (bool, error)
|
||||
@@ -59,6 +67,11 @@ type HandlerConfig struct {
|
||||
|
||||
// Handle handles the given resource and returns a boolean to say if the tenantControlPlane has been modified.
|
||||
func Handle(ctx context.Context, resource Resource, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
resource.GetHistogram().Observe(time.Since(startTime).Seconds())
|
||||
}()
|
||||
|
||||
if err := resource.Define(ctx, tenantControlPlane); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
@@ -28,6 +29,12 @@ type SACertificate struct {
|
||||
TmpDirectory string
|
||||
}
|
||||
|
||||
func (r *SACertificate) GetHistogram() prometheus.Histogram {
|
||||
serviceaccountcertificateCollector = LazyLoadHistogramFromResource(serviceaccountcertificateCollector, r)
|
||||
|
||||
return serviceaccountcertificateCollector
|
||||
}
|
||||
|
||||
func (r *SACertificate) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return tenantControlPlane.Status.Certificates.SA.SecretName != r.resource.GetName() ||
|
||||
tenantControlPlane.Status.Certificates.SA.Checksum != utilities.GetObjectChecksum(r.resource)
|
||||
@@ -84,7 +91,9 @@ func (r *SACertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1
|
||||
return func() error {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.SA.Checksum; len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0 {
|
||||
isRotationRequested := utilities.IsRotationRequested(r.resource)
|
||||
|
||||
if checksum := tenantControlPlane.Status.Certificates.SA.Checksum; !isRotationRequested && (len(checksum) > 0 && checksum == utilities.GetObjectChecksum(r.resource) || len(r.resource.UID) > 0) {
|
||||
isValid, err := crypto.CheckPublicAndPrivateKeyValidity(r.resource.Data[kubeadmconstants.ServiceAccountPublicKeyName], r.resource.Data[kubeadmconstants.ServiceAccountPrivateKeyName])
|
||||
if err != nil {
|
||||
logger.Info(fmt.Sprintf("%s public_key-private_key pair is not valid: %s", kubeadmconstants.ServiceAccountKeyBaseName, err.Error()))
|
||||
@@ -115,6 +124,10 @@ func (r *SACertificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1
|
||||
|
||||
r.resource.SetLabels(utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()))
|
||||
|
||||
if isRotationRequested {
|
||||
utilities.SetLastRotationTimestamp(r.resource)
|
||||
}
|
||||
|
||||
utilities.SetObjectChecksum(r.resource, r.resource.Data)
|
||||
|
||||
return ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme())
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
package upgrade
|
||||
|
||||
const (
|
||||
KubeadmVersion = "v1.33.0"
|
||||
KubeadmVersion = "v1.33.2"
|
||||
)
|
||||
|
||||
40
internal/utilities/certs_rotation.go
Normal file
40
internal/utilities/certs_rotation.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package utilities
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
const (
|
||||
RotateCertificateRequestAnnotation = "certs.kamaji.clastix.io/rotate"
|
||||
|
||||
CertificateX509Label = "x509"
|
||||
CertificateKubeconfigLabel = "kubeconfig"
|
||||
)
|
||||
|
||||
func IsRotationRequested(obj client.Object) bool {
|
||||
if obj.GetAnnotations() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
v, ok := obj.GetAnnotations()[RotateCertificateRequestAnnotation]
|
||||
if ok && v == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func SetLastRotationTimestamp(obj client.Object) {
|
||||
annotations := obj.GetAnnotations()
|
||||
if annotations == nil {
|
||||
annotations = map[string]string{}
|
||||
}
|
||||
|
||||
annotations[RotateCertificateRequestAnnotation] = metav1.Now().String()
|
||||
|
||||
obj.SetAnnotations(annotations)
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
package internal
|
||||
|
||||
var (
|
||||
ContainerRepository = "docker.io"
|
||||
|
||||
GitRepo = ""
|
||||
GitTag = "dev"
|
||||
GitCommit = ""
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/webhook/utils"
|
||||
)
|
||||
|
||||
type TenantControlPlaneKubeletAddresses struct{}
|
||||
|
||||
func (t TenantControlPlaneKubeletAddresses) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
return nil, t.validatePreferredKubeletAddressTypes(tcp.Spec.Kubernetes.Kubelet.PreferredAddressTypes)
|
||||
}
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneKubeletAddresses) OnDelete(runtime.Object) AdmissionResponse {
|
||||
return utils.NilOp()
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneKubeletAddresses) OnUpdate(object runtime.Object, _ runtime.Object) AdmissionResponse {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
return nil, t.validatePreferredKubeletAddressTypes(tcp.Spec.Kubernetes.Kubelet.PreferredAddressTypes)
|
||||
}
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneKubeletAddresses) validatePreferredKubeletAddressTypes(addressTypes []kamajiv1alpha1.KubeletPreferredAddressType) error {
|
||||
s := sets.New[string]()
|
||||
|
||||
for _, at := range addressTypes {
|
||||
if s.Has(string(at)) {
|
||||
return fmt.Errorf("preferred kubelet address types is stated multiple times: %s", at)
|
||||
}
|
||||
|
||||
s.Insert(string(at))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user