mirror of
https://github.com/clastix/kamaji.git
synced 2026-02-28 16:50:29 +00:00
Compare commits
40 Commits
helm-v0.16
...
edge-24.8.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1731e8c2ed | ||
|
|
5addb80f91 | ||
|
|
d8a86edcec | ||
|
|
d2f3cfda24 | ||
|
|
535257935d | ||
|
|
8cdc619124 | ||
|
|
ea5799420e | ||
|
|
a16d2c5e98 | ||
|
|
a33c16fbbd | ||
|
|
d8dfc62794 | ||
|
|
033a18f8f9 | ||
|
|
a1700fcde5 | ||
|
|
5274a91c0c | ||
|
|
710ad4da8a | ||
|
|
7a2c02996b | ||
|
|
beeb66b552 | ||
|
|
810eec9e8c | ||
|
|
7f5cb3ab7c | ||
|
|
b6cb9d2bee | ||
|
|
e812136d61 | ||
|
|
d4d38c8eaf | ||
|
|
2e17d6b701 | ||
|
|
00356d8c97 | ||
|
|
3b75b23e05 | ||
|
|
a707c618d5 | ||
|
|
84e669316a | ||
|
|
2e235a4e32 | ||
|
|
52c1ee8aba | ||
|
|
b541962163 | ||
|
|
f4c0cec4f9 | ||
|
|
db3a092d3d | ||
|
|
d590b9d17d | ||
|
|
9147ae9977 | ||
|
|
d2ff044228 | ||
|
|
a147869944 | ||
|
|
056ad4002a | ||
|
|
91cbf0c507 | ||
|
|
d57d5b5a56 | ||
|
|
24714d7168 | ||
|
|
422d225682 |
20
.github/dependabot.yml
vendored
Normal file
20
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
rebase-strategy: disabled
|
||||
commit-message:
|
||||
prefix: "feat(deps)"
|
||||
groups:
|
||||
arrow:
|
||||
patterns:
|
||||
- "k8s.io*"
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
rebase-strategy: disabled
|
||||
commit-message:
|
||||
prefix: "chore(ci)"
|
||||
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@@ -12,12 +12,12 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
check-latest: true
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3.2.0
|
||||
uses: golangci/golangci-lint-action@v6.1.0
|
||||
with:
|
||||
version: v1.54.2
|
||||
only-new-issues: false
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
check-latest: true
|
||||
|
||||
1
.github/workflows/docker-ci.yml
vendored
1
.github/workflows/docker-ci.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
- "edge-*"
|
||||
|
||||
jobs:
|
||||
docker-ci:
|
||||
|
||||
4
.github/workflows/e2e.yaml
vendored
4
.github/workflows/e2e.yaml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
paths:
|
||||
- '.github/workflows/e2e.yml'
|
||||
- 'api/**'
|
||||
- 'charts/kamaji/**'
|
||||
- 'controllers/**'
|
||||
- 'e2e/*'
|
||||
- 'Dockerfile'
|
||||
@@ -19,6 +20,7 @@ on:
|
||||
paths:
|
||||
- '.github/workflows/e2e.yml'
|
||||
- 'api/**'
|
||||
- 'charts/kamaji/**'
|
||||
- 'controllers/**'
|
||||
- 'e2e/*'
|
||||
- 'Dockerfile'
|
||||
@@ -36,7 +38,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
check-latest: true
|
||||
|
||||
4
.github/workflows/helm.yaml
vendored
4
.github/workflows/helm.yaml
vendored
@@ -25,6 +25,10 @@ jobs:
|
||||
- uses: azure/setup-helm@v1
|
||||
with:
|
||||
version: 3.3.4
|
||||
- name: Building dependencies
|
||||
run: |-
|
||||
helm repo add clastix https://clastix.github.io/charts
|
||||
helm dependency build ./charts/kamaji
|
||||
- name: Linting Chart
|
||||
run: helm lint ./charts/kamaji
|
||||
release:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -37,3 +37,4 @@ bin
|
||||
**/server-csr.json
|
||||
!deploy/kine/mysql/server-csr.json
|
||||
!deploy/kine/nats/server-csr.json
|
||||
charts/kamaji/charts
|
||||
|
||||
@@ -3,7 +3,7 @@ linters-settings:
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- prefix(github.com/clastix/kamaji)
|
||||
- prefix(github.com/clastix/kamaji/)
|
||||
goheader:
|
||||
template: |-
|
||||
Copyright 2022 Clastix Labs
|
||||
|
||||
@@ -7,6 +7,7 @@ Feel free to open a Pull-Request to get yours listed.
|
||||
|
||||
| Type | Name | Since | Website | Use-Case |
|
||||
|:-|:-|:-|:-|:-|
|
||||
| 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). |
|
||||
| End-user | Sicuro Tech Lab | 2024 | [link](https://sicurotechlab.it/) | Sicuro Tech Lab offers cloud infrastructure for Web Agencies and uses kamaji to provide managed k8s services. |
|
||||
| R&D | TIM | 2024 | [link](https://www.gruppotim.it) | TIM is an Italian telecommunications company using Kamaji for experimental research and development purposes. |
|
||||
| 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). |
|
||||
|
||||
8
Makefile
8
Makefile
@@ -3,7 +3,7 @@
|
||||
# To re-generate a bundle for another specific version without changing the standard setup, you can:
|
||||
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
|
||||
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
|
||||
VERSION ?= 0.6.1
|
||||
VERSION ?= 1.0.0
|
||||
|
||||
# CHANNELS define the bundle channels used in the bundle.
|
||||
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
|
||||
@@ -77,7 +77,7 @@ helm: ## Download helm locally if necessary.
|
||||
|
||||
GINKGO = $(shell pwd)/bin/ginkgo
|
||||
ginkgo: ## Download ginkgo locally if necessary.
|
||||
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo@v2.6.0)
|
||||
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo)
|
||||
|
||||
KIND = $(shell pwd)/bin/kind
|
||||
kind: ## Download kind locally if necessary.
|
||||
@@ -307,7 +307,9 @@ env:
|
||||
|
||||
.PHONY: e2e
|
||||
e2e: env load helm ginkgo cert-manager ## Create a KinD cluster, install Kamaji on it and run the test suite.
|
||||
$(HELM) upgrade --debug --install kamaji ./charts/kamaji --create-namespace --namespace kamaji-system --set "image.pullPolicy=Never"
|
||||
$(HELM) repo add clastix https://clastix.github.io/charts
|
||||
$(HELM) dependency build ./charts/kamaji
|
||||
$(HELM) upgrade --debug --install kamaji ./charts/kamaji --create-namespace --namespace kamaji-system --set "image.pullPolicy=Never" --set "telemetry.disabled=true"
|
||||
$(MAKE) datastores
|
||||
$(GINKGO) -v ./e2e
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ Since Kamaji is just focusing on the Control Plane a [Kamaji's Cluster API Contr
|
||||
- YouTube ▶️ [Equinix, Kamaji, and Cluster API](https://www.youtube.com/watch?v=TLBTqROj_wA)
|
||||
- YouTube ▶️ [Rancher & Kamaji: solving multitenancy challenges in the Kubernetes world](https://www.youtube.com/watch?v=VXHNrMmlF8U)
|
||||
- YouTube ▶️ [Enabling Self-Service Kubernetes clusters with Kamaji and Paralus](https://www.youtube.com/watch?v=JWA2LwZazM0)
|
||||
- YouTube ▶️ [Hosted Control Plane on Kubernetes (HPC) with Kamaji and K0mostron by Hervé Leclerc, ALTER WAY](https://www.youtube.com/watch?v=vmRdE2ngn78)
|
||||
|
||||
### 🏷️ Versioning
|
||||
|
||||
@@ -157,4 +158,4 @@ The code is provided as-is with no warranties.
|
||||
If you're looking to run Kamaji in production and would like to learn more, **CLASTIX** can help by offering [Open Source support plans](https://clastix.io/support),
|
||||
as well as providing a comprehensive Enterprise Platform named [CLASTIX Enterprise Platform](https://clastix.cloud/), built on top of the Kamaji and [Capsule](https://capsule.clastix.io/) project (now donated to CNCF as a Sandbox project).
|
||||
|
||||
Feel free to get in touch with the provided [Contact form](https://clastix.io/contact).
|
||||
Feel free to get in touch with the provided [Contact form](https://clastix.io/contact).
|
||||
|
||||
@@ -204,7 +204,7 @@ type KonnectivityServerSpec struct {
|
||||
// The port which Konnectivity server is listening to.
|
||||
Port int32 `json:"port"`
|
||||
// Container image version of the Konnectivity server.
|
||||
// +kubebuilder:default=v0.0.32
|
||||
// +kubebuilder:default=v0.28.6
|
||||
Version string `json:"version,omitempty"`
|
||||
// Container image used by the Konnectivity server.
|
||||
// +kubebuilder:default=registry.k8s.io/kas-network-proxy/proxy-server
|
||||
@@ -219,7 +219,7 @@ type KonnectivityAgentSpec struct {
|
||||
// +kubebuilder:default=registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
Image string `json:"image,omitempty"`
|
||||
// Version for Konnectivity agent.
|
||||
// +kubebuilder:default=v0.0.32
|
||||
// +kubebuilder:default=v0.28.6
|
||||
Version string `json:"version,omitempty"`
|
||||
// Tolerations for the deployed agent.
|
||||
// Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.
|
||||
@@ -230,9 +230,9 @@ type KonnectivityAgentSpec struct {
|
||||
|
||||
// KonnectivitySpec defines the spec for Konnectivity.
|
||||
type KonnectivitySpec struct {
|
||||
// +kubebuilder:default={version:"v0.0.32",image:"registry.k8s.io/kas-network-proxy/proxy-server",port:8132}
|
||||
// +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.0.32",image:"registry.k8s.io/kas-network-proxy/proxy-agent"}
|
||||
// +kubebuilder:default={version:"v0.28.6",image:"registry.k8s.io/kas-network-proxy/proxy-agent"}
|
||||
KonnectivityAgentSpec KonnectivityAgentSpec `json:"agent,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
6
charts/kamaji/Chart.lock
Normal file
6
charts/kamaji/Chart.lock
Normal file
@@ -0,0 +1,6 @@
|
||||
dependencies:
|
||||
- name: kamaji-etcd
|
||||
repository: https://clastix.github.io/charts
|
||||
version: 0.7.0
|
||||
digest: sha256:2e23a11b06da2aa3a935a56a93d56876c6c8ef0a7800ee44070f9a269dfbca71
|
||||
generated: "2024-08-10T23:03:35.382486587+02:00"
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: v0.6.1
|
||||
appVersion: v1.0.0
|
||||
description: Kamaji is the Hosted Control Plane Manager for Kubernetes.
|
||||
home: https://github.com/clastix/kamaji
|
||||
icon: https://github.com/clastix/kamaji/raw/master/assets/logo-colored.png
|
||||
@@ -17,8 +17,33 @@ name: kamaji
|
||||
sources:
|
||||
- https://github.com/clastix/kamaji
|
||||
type: application
|
||||
version: 0.16.1
|
||||
version: 2.0.0
|
||||
dependencies:
|
||||
- name: kamaji-etcd
|
||||
repository: https://clastix.github.io/charts
|
||||
version: ">=0.7.0"
|
||||
condition: kamaji-etcd.deploy
|
||||
annotations:
|
||||
catalog.cattle.io/certified: partner
|
||||
catalog.cattle.io/release-name: kamaji
|
||||
catalog.cattle.io/display-name: Kamaji
|
||||
artifacthub.io/crds: |
|
||||
- kind: TenantControlPlane
|
||||
version: v1alpha1
|
||||
name: tenantcontrolplanes.kamaji.clastix.io
|
||||
displayName: TenantControlPlane
|
||||
description: TenantControlPlane defines the desired state for a Control Plane backed by Kamaji.
|
||||
- kind: DataStore
|
||||
version: v1alpha1
|
||||
name: datastores.kamaji.clastix.io
|
||||
displayName: DataStore
|
||||
description: DataStores is holding all the required details to communicate with a Datastore, such as etcd, MySQL, PostgreSQL, and NATS.
|
||||
artifacthub.io/links: |
|
||||
- name: CLASTIX
|
||||
url: https://clastix.io
|
||||
- name: support
|
||||
url: https://clastix.io/support
|
||||
artifacthub.io/operator: "true"
|
||||
artifacthub.io/operatorCapabilities: "full lifecycle"
|
||||
artifacthub.io/changes: |
|
||||
- Using dependency chart `kamaji-etcd` as a default DataStore.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# kamaji
|
||||
|
||||
  
|
||||
  
|
||||
|
||||
Kamaji is the Hosted Control Plane Manager for Kubernetes.
|
||||
|
||||
@@ -20,6 +20,10 @@ Kamaji is the Hosted Control Plane Manager for Kubernetes.
|
||||
|
||||
Kubernetes: `>=1.21.0-0`
|
||||
|
||||
| Repository | Name | Version |
|
||||
|------------|------|---------|
|
||||
| https://clastix.github.io/charts | kamaji-etcd | >=0.7.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`.
|
||||
|
||||
@@ -66,49 +70,7 @@ Here the values you can override:
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| affinity | object | `{}` | Kubernetes affinity rules to apply to Kamaji controller pods |
|
||||
| cfssl.image.repository | string | `"cfssl/cfssl"` | |
|
||||
| cfssl.image.tag | string | `"latest"` | |
|
||||
| datastore.basicAuth.passwordSecret.keyPath | string | `nil` | The Secret key where the data is stored. |
|
||||
| datastore.basicAuth.passwordSecret.name | string | `nil` | The name of the Secret containing the password used to connect to the relational database. |
|
||||
| datastore.basicAuth.passwordSecret.namespace | string | `nil` | The namespace of the Secret containing the password used to connect to the relational database. |
|
||||
| datastore.basicAuth.usernameSecret.keyPath | string | `nil` | The Secret key where the data is stored. |
|
||||
| datastore.basicAuth.usernameSecret.name | string | `nil` | The name of the Secret containing the username used to connect to the relational database. |
|
||||
| datastore.basicAuth.usernameSecret.namespace | string | `nil` | The namespace of the Secret containing the username used to connect to the relational database. |
|
||||
| datastore.driver | string | `"etcd"` | (string) The Kamaji Datastore driver, supported: etcd, MySQL, PostgreSQL (defaults=etcd). |
|
||||
| datastore.enabled | bool | `true` | (bool) Enable the Kamaji Datastore creation (default=true) |
|
||||
| datastore.endpoints | list | `[]` | (array) List of endpoints of the selected Datastore. When letting the Chart install the etcd datastore, this field is populated automatically. |
|
||||
| datastore.nameOverride | string | `nil` | The Datastore name override, if empty and enabled=true defaults to `default`, if enabled=false, this is the name of the Datastore to connect to. |
|
||||
| datastore.tlsConfig.certificateAuthority.certificate.keyPath | string | `nil` | Key of the Secret which contains the content of the certificate. |
|
||||
| datastore.tlsConfig.certificateAuthority.certificate.name | string | `nil` | Name of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.certificateAuthority.certificate.namespace | string | `nil` | Namespace of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.certificateAuthority.privateKey.keyPath | string | `nil` | Key of the Secret which contains the content of the private key. |
|
||||
| datastore.tlsConfig.certificateAuthority.privateKey.name | string | `nil` | Name of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.certificateAuthority.privateKey.namespace | string | `nil` | Namespace of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.clientCertificate.certificate.keyPath | string | `nil` | Key of the Secret which contains the content of the certificate. |
|
||||
| datastore.tlsConfig.clientCertificate.certificate.name | string | `nil` | Name of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.clientCertificate.certificate.namespace | string | `nil` | Namespace of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.clientCertificate.privateKey.keyPath | string | `nil` | Key of the Secret which contains the content of the private key. |
|
||||
| datastore.tlsConfig.clientCertificate.privateKey.name | string | `nil` | Name of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.clientCertificate.privateKey.namespace | string | `nil` | Namespace of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore. |
|
||||
| datastore.tlsConfig.enabled | bool | `true` | |
|
||||
| etcd.compactionInterval | int | `0` | ETCD Compaction interval (e.g. "5m0s"). (default: "0" (disabled)) |
|
||||
| etcd.deploy | bool | `true` | Install an etcd with enabled multi-tenancy along with Kamaji |
|
||||
| etcd.image | object | `{"pullPolicy":"IfNotPresent","repository":"quay.io/coreos/etcd","tag":"v3.5.6"}` | Install specific etcd image |
|
||||
| etcd.livenessProbe | object | `{"failureThreshold":8,"httpGet":{"path":"/health?serializable=true","port":2381,"scheme":"HTTP"},"initialDelaySeconds":10,"periodSeconds":10,"timeoutSeconds":15}` | The livenessProbe for the etcd container |
|
||||
| etcd.overrides.caSecret.name | string | `"etcd-certs"` | Name of the secret which contains CA's certificate and private key. (default: "etcd-certs") |
|
||||
| etcd.overrides.caSecret.namespace | string | `"kamaji-system"` | Namespace of the secret which contains CA's certificate and private key. (default: "kamaji-system") |
|
||||
| etcd.overrides.clientSecret.name | string | `"root-client-certs"` | Name of the secret which contains ETCD client certificates. (default: "root-client-certs") |
|
||||
| etcd.overrides.clientSecret.namespace | string | `"kamaji-system"` | Name of the namespace where the secret which contains ETCD client certificates is. (default: "kamaji-system") |
|
||||
| etcd.overrides.endpoints | object | `{"etcd-0":"etcd-0.etcd.kamaji-system.svc.cluster.local","etcd-1":"etcd-1.etcd.kamaji-system.svc.cluster.local","etcd-2":"etcd-2.etcd.kamaji-system.svc.cluster.local"}` | (map) Dictionary of the endpoints for the etcd cluster's members, key is the name of the etcd server. Don't define the protocol (TLS is automatically inflected), or any port, inflected from .etcd.peerApiPort value. |
|
||||
| etcd.peerApiPort | int | `2380` | The peer API port which servers are listening to. |
|
||||
| etcd.persistence.accessModes[0] | string | `"ReadWriteOnce"` | |
|
||||
| etcd.persistence.customAnnotations | object | `{}` | The custom annotations to add to the PVC |
|
||||
| etcd.persistence.size | string | `"10Gi"` | |
|
||||
| etcd.persistence.storageClassName | string | `""` | |
|
||||
| etcd.port | int | `2379` | The client request port. |
|
||||
| etcd.serviceAccount.create | bool | `true` | Create a ServiceAccount, required to install and provision the etcd backing storage (default: true) |
|
||||
| etcd.serviceAccount.name | string | `""` | Define the ServiceAccount name to use during the setup and provision of the etcd backing storage (default: "") |
|
||||
| etcd.tolerations | list | `[]` | (array) Kubernetes affinity rules to apply to Kamaji etcd pods |
|
||||
| defaultDatastoreName | string | `"default"` | Specify the default DataStore name for the Kamaji instance. |
|
||||
| extraArgs | list | `[]` | A list of extra arguments to add to the kamaji controller default ones |
|
||||
| fullnameOverride | string | `""` | |
|
||||
| healthProbeBindAddress | string | `":8081"` | The address the probe endpoint binds to. (default ":8081") |
|
||||
@@ -116,9 +78,13 @@ 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"` | |
|
||||
| livenessProbe | object | `{"httpGet":{"path":"/healthz","port":"healthcheck"},"initialDelaySeconds":15,"periodSeconds":20}` | The livenessProbe for the controller container |
|
||||
| loggingDevel.enable | bool | `false` | (string) Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false) |
|
||||
| metricsBindAddress | string | `":8080"` | (string) The address the metric endpoint binds to. (default ":8080") |
|
||||
| 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") |
|
||||
| nameOverride | string | `""` | |
|
||||
| nodeSelector | object | `{}` | Kubernetes node selector rules to schedule Kamaji controller |
|
||||
| podAnnotations | object | `{}` | The annotations to apply to the Kamaji controller pods. |
|
||||
@@ -134,6 +100,7 @@ Here the values you can override:
|
||||
| serviceAccount.create | bool | `true` | |
|
||||
| serviceAccount.name | string | `"kamaji-controller-manager"` | |
|
||||
| serviceMonitor.enabled | bool | `false` | Toggle the ServiceMonitor true if you have Prometheus Operator installed and configured |
|
||||
| telemetry | object | `{"disabled":false}` | Disable the analytics traces collection |
|
||||
| temporaryDirectoryPath | string | `"/tmp/kamaji"` | Directory which will be used to work with temporary files. (default "/tmp/kamaji") |
|
||||
| tolerations | list | `[]` | Kubernetes node taints that the Kamaji controller pods would tolerate |
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ spec:
|
||||
agent:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
version: v0.0.32
|
||||
version: v0.28.6
|
||||
properties:
|
||||
extraArgs:
|
||||
description: |-
|
||||
@@ -165,7 +165,7 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
version:
|
||||
default: v0.0.32
|
||||
default: v0.28.6
|
||||
description: Version for Konnectivity agent.
|
||||
type: string
|
||||
type: object
|
||||
@@ -173,7 +173,7 @@ spec:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-server
|
||||
port: 8132
|
||||
version: v0.0.32
|
||||
version: v0.28.6
|
||||
properties:
|
||||
extraArgs:
|
||||
description: |-
|
||||
@@ -252,7 +252,7 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
default: v0.0.32
|
||||
default: v0.28.6
|
||||
description: Container image version of the Konnectivity
|
||||
server.
|
||||
type: string
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
{{/*
|
||||
Create a default fully qualified datastore name.
|
||||
*/}}
|
||||
{{- define "datastore.fullname" -}}
|
||||
{{- if .Values.datastore.enabled }}
|
||||
{{- default "default" .Values.datastore.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- required "A valid .Values.datastore.nameOverride required!" .Values.datastore.nameOverride }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "datastore.labels" -}}
|
||||
kamaji.clastix.io/datastore: {{ .Values.datastore.driver }}
|
||||
helm.sh/chart: {{ include "kamaji.chart" . }}
|
||||
{{ include "kamaji.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Datastore endpoints, in case of ETCD, retrieving the one provided by the chart.
|
||||
*/}}
|
||||
{{- define "datastore.endpoints" -}}
|
||||
{{- if eq .Values.datastore.driver "etcd" }}
|
||||
{{ include "etcd.endpoints" . }}
|
||||
{{- else }}
|
||||
{{ .Values.datastore.endpoints }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
The Certificate Authority section for the DataSource object.
|
||||
*/}}
|
||||
{{- define "datastore.certificateAuthority" -}}
|
||||
{{- if eq .Values.datastore.driver "etcd" }}
|
||||
certificate:
|
||||
secretReference:
|
||||
name: {{ include "etcd.caSecretName" . }}
|
||||
namespace: {{ include "etcd.caSecretNamespace" . }}
|
||||
keyPath: ca.crt
|
||||
privateKey:
|
||||
secretReference:
|
||||
name: {{ include "etcd.caSecretName" . }}
|
||||
namespace: {{ include "etcd.caSecretNamespace" . }}
|
||||
keyPath: ca.key
|
||||
{{- else }}
|
||||
certificate:
|
||||
secretReference:
|
||||
name: {{ .Values.datastore.tlsConfig.certificateAuthority.certificate.name }}
|
||||
namespace: {{ .Values.datastore.tlsConfig.certificateAuthority.certificate.namespace }}
|
||||
keyPath: {{ .Values.datastore.tlsConfig.certificateAuthority.certificate.keyPath }}
|
||||
{{- if .Values.datastore.tlsConfig.certificateAuthority.privateKey.name }}
|
||||
privateKey:
|
||||
secretReference:
|
||||
name: {{ .Values.datastore.tlsConfig.certificateAuthority.privateKey.name }}
|
||||
namespace: {{ .Values.datastore.tlsConfig.certificateAuthority.privateKey.namespace }}
|
||||
keyPath: {{ .Values.datastore.tlsConfig.certificateAuthority.privateKey.keyPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
The Client Certificate section for the DataSource object.
|
||||
*/}}
|
||||
{{- define "datastore.clientCertificate" -}}
|
||||
{{- if eq .Values.datastore.driver "etcd" }}
|
||||
certificate:
|
||||
secretReference:
|
||||
name: {{ include "etcd.clientSecretName" . }}
|
||||
namespace: {{ include "etcd.clientSecretNamespace" . }}
|
||||
keyPath: tls.crt
|
||||
privateKey:
|
||||
secretReference:
|
||||
name: {{ include "etcd.clientSecretName" . }}
|
||||
namespace: {{ include "etcd.clientSecretNamespace" . }}
|
||||
keyPath: tls.key
|
||||
{{- else }}
|
||||
certificate:
|
||||
secretReference:
|
||||
name: {{ .Values.datastore.tlsConfig.clientCertificate.certificate.name }}
|
||||
namespace: {{ .Values.datastore.tlsConfig.clientCertificate.certificate.namespace }}
|
||||
keyPath: {{ .Values.datastore.tlsConfig.clientCertificate.certificate.keyPath }}
|
||||
privateKey:
|
||||
secretReference:
|
||||
name: {{ .Values.datastore.tlsConfig.clientCertificate.privateKey.name }}
|
||||
namespace: {{ .Values.datastore.tlsConfig.clientCertificate.privateKey.namespace }}
|
||||
keyPath: {{ .Values.datastore.tlsConfig.clientCertificate.privateKey.keyPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,142 +0,0 @@
|
||||
{{/*
|
||||
Create a default fully qualified etcd name.
|
||||
*/}}
|
||||
{{- define "etcd.fullname" -}}
|
||||
{{- printf "etcd" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "etcd.serviceAccountName" -}}
|
||||
{{- if .Values.etcd.serviceAccount.create }}
|
||||
{{- default (include "etcd.fullname" .) .Values.etcd.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.etcd.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the Service to use
|
||||
*/}}
|
||||
{{- define "etcd.serviceName" -}}
|
||||
{{- printf "%s" (include "etcd.fullname" .) | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "etcd.labels" -}}
|
||||
app.kubernetes.io/name: {{ include "kamaji.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/components: etcd
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels.
|
||||
*/}}
|
||||
{{- define "etcd.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "kamaji.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: etcd
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Name of the etcd CA secret.
|
||||
*/}}
|
||||
{{- define "etcd.caSecretName" }}
|
||||
{{- if .Values.etcd.deploy }}
|
||||
{{- printf "%s-%s" (include "etcd.fullname" .) "certs" | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- required "A valid .Values.etcd.overrides.caSecret.name required!" .Values.etcd.overrides.caSecret.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Namespace of the etcd CA secret.
|
||||
*/}}
|
||||
{{- define "etcd.caSecretNamespace" }}
|
||||
{{- if .Values.etcd.deploy }}
|
||||
{{- .Release.Namespace }}
|
||||
{{- else }}
|
||||
{{- required "A valid .Values.etcd.overrides.caSecret.namespace required!" .Values.etcd.overrides.caSecret.namespace }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Name of the certificate signing requests for the certificates required by etcd.
|
||||
*/}}
|
||||
{{- define "etcd.csrConfigMapName" }}
|
||||
{{- printf "%s-csr" (include "etcd.fullname" .) }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Name of the etcd root-client secret.
|
||||
*/}}
|
||||
{{- define "etcd.clientSecretName" }}
|
||||
{{- if .Values.etcd.deploy }}
|
||||
{{- printf "root-client-certs" }}
|
||||
{{- else }}
|
||||
{{- required "A valid .Values.etcd.overrides.clientSecret.name required!" .Values.etcd.overrides.clientSecret.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Namespace of the etcd root-client secret.
|
||||
*/}}
|
||||
{{- define "etcd.clientSecretNamespace" }}
|
||||
{{- if .Values.etcd.deploy }}
|
||||
{{- .Release.Namespace }}
|
||||
{{- else }}
|
||||
{{- required "A valid .Values.etcd.overrides.clientSecret.namespace required!" .Values.etcd.overrides.clientSecret.namespace }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Comma separated list of etcd endpoints, using the overrides in case of unmanaged etcd.
|
||||
*/}}
|
||||
{{- define "etcd.endpoints" }}
|
||||
{{- $list := list -}}
|
||||
{{- if .Values.etcd.deploy }}
|
||||
{{- range $count := until 3 -}}
|
||||
{{- $list = append $list (printf "%s-%d.%s.%s.svc.cluster.local:%d" "etcd" $count ( include "etcd.serviceName" . ) $.Release.Namespace (int $.Values.etcd.port) ) -}}
|
||||
{{- end }}
|
||||
{{- else if .Values.etcd.overrides.endpoints }}
|
||||
{{- range $v := .Values.etcd.overrides.endpoints -}}
|
||||
{{- $list = append $list (printf "%s:%d" $v (int $.Values.etcd.port) ) -}}
|
||||
{{- end -}}
|
||||
{{- else if not .Values.etcd.overrides.endpoints }}
|
||||
{{- fail "A valid .Values.etcd.overrides.endpoints required!" }}
|
||||
{{- end }}
|
||||
{{- $list | toYaml }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Key-value of the etcd peers, using the overrides in case of unmanaged etcd.
|
||||
*/}}
|
||||
{{- define "etcd.initialCluster" }}
|
||||
{{- $list := list -}}
|
||||
{{- if .Values.etcd.deploy }}
|
||||
{{- range $i, $count := until 3 -}}
|
||||
{{- $list = append $list ( printf "etcd-%d=https://%s-%d.%s.%s.svc.cluster.local:%d" $i "etcd" $count ( include "etcd.serviceName" . ) $.Release.Namespace (int $.Values.etcd.peerApiPort) ) -}}
|
||||
{{- end }}
|
||||
{{- else if .Values.etcd.overrides.endpoints }}
|
||||
{{- range $k, $v := .Values.etcd.overrides.endpoints -}}
|
||||
{{- $list = append $list ( printf "%s=%s:%d" $k $v (int $.Values.etcd.peerApiPort) ) -}}
|
||||
{{- end -}}
|
||||
{{- else if not .Values.etcd.overrides.endpoints }}
|
||||
{{- fail "A valid .Values.etcd.overrides.endpoints required!" }}
|
||||
{{- end }}
|
||||
{{- join "," $list -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Retrieve the current Kubernetes version to launch a kubectl container with the minimum version skew possible.
|
||||
*/}}
|
||||
{{- define "etcd.jobsTagKubeVersion" -}}
|
||||
{{- if contains "-eks-" .Capabilities.KubeVersion.GitVersion }}
|
||||
{{- print "v" .Capabilities.KubeVersion.Major "." (.Capabilities.KubeVersion.Minor | replace "+" "") -}}
|
||||
{{- else }}
|
||||
{{- print "v" .Capabilities.KubeVersion.Major "." .Capabilities.KubeVersion.Minor -}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -33,7 +33,11 @@ spec:
|
||||
- --leader-elect
|
||||
- --metrics-bind-address={{ .Values.metricsBindAddress }}
|
||||
- --tmp-directory={{ .Values.temporaryDirectoryPath }}
|
||||
- --datastore={{ include "datastore.fullname" . }}
|
||||
{{- $datastoreName := .Values.defaultDatastoreName | required ".Values.defaultDatastoreName is required!" }}
|
||||
- --datastore={{ $datastoreName }}
|
||||
{{- if .Values.telemetry.disabled }}
|
||||
- --disable-telemetry
|
||||
{{- end }}
|
||||
{{- if .Values.loggingDevel.enable }}
|
||||
- --zap-devel
|
||||
{{- end }}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
{{- if .Values.datastore.enabled}}
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: DataStore
|
||||
metadata:
|
||||
name: {{ include "datastore.fullname" . }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install
|
||||
labels:
|
||||
{{- include "datastore.labels" . | nindent 4 }}
|
||||
spec:
|
||||
driver: {{ .Values.datastore.driver }}
|
||||
endpoints:
|
||||
{{- include "datastore.endpoints" . | indent 4 }}
|
||||
{{- if (and .Values.datastore.basicAuth.usernameSecret.name .Values.datastore.basicAuth.passwordSecret.name) }}
|
||||
basicAuth:
|
||||
username:
|
||||
secretReference:
|
||||
{{- .Values.datastore.basicAuth.usernameSecret | toYaml | nindent 8 }}
|
||||
password:
|
||||
secretReference:
|
||||
{{- .Values.datastore.basicAuth.passwordSecret | toYaml | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.datastore.tlsConfig.enabled }}
|
||||
tlsConfig:
|
||||
certificateAuthority:
|
||||
{{- include "datastore.certificateAuthority" . | indent 6 }}
|
||||
|
||||
{{- if .Values.datastore.tlsConfig.clientCertificate }}
|
||||
clientCertificate:
|
||||
{{- include "datastore.clientCertificate" . | indent 6 }}
|
||||
{{- end }}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
@@ -1,98 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
name: {{ include "etcd.csrConfigMapName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install
|
||||
"helm.sh/hook-weight": "-5"
|
||||
"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"
|
||||
data:
|
||||
ca-csr.json: |-
|
||||
{
|
||||
"CN": "Clastix CA",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"names": [
|
||||
{
|
||||
"C": "IT",
|
||||
"ST": "Italy",
|
||||
"L": "Milan"
|
||||
}
|
||||
]
|
||||
}
|
||||
config.json: |-
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"expiry": "8760h"
|
||||
},
|
||||
"profiles": {
|
||||
"server-authentication": {
|
||||
"usages": ["signing", "key encipherment", "server auth"],
|
||||
"expiry": "8760h"
|
||||
},
|
||||
"client-authentication": {
|
||||
"usages": ["signing", "key encipherment", "client auth"],
|
||||
"expiry": "8760h"
|
||||
},
|
||||
"peer-authentication": {
|
||||
"usages": ["signing", "key encipherment", "server auth", "client auth"],
|
||||
"expiry": "8760h"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
server-csr.json: |-
|
||||
{
|
||||
"CN": "etcd",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [
|
||||
{{- range $count := until 3 -}}
|
||||
{{ printf "\"etcd-%d.%s.%s.svc.cluster.local\"," $count (include "etcd.serviceName" .) $.Release.Namespace }}
|
||||
{{- end }}
|
||||
"etcd-server.{{ .Release.Namespace }}.svc.cluster.local",
|
||||
"etcd-server.{{ .Release.Namespace }}.svc",
|
||||
"etcd-server",
|
||||
"127.0.0.1"
|
||||
]
|
||||
}
|
||||
peer-csr.json: |-
|
||||
{
|
||||
"CN": "etcd",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [
|
||||
{{- range $count := until 3 -}}
|
||||
{{ printf "\"etcd-%d\"," $count }}
|
||||
{{ printf "\"etcd-%d.%s\"," $count (include "etcd.serviceName" .) }}
|
||||
{{ printf "\"etcd-%d.%s.%s.svc\"," $count (include "etcd.serviceName" .) $.Release.Namespace }}
|
||||
{{ printf "\"etcd-%d.%s.%s.svc.cluster.local\"," $count (include "etcd.serviceName" .) $.Release.Namespace }}
|
||||
{{- end }}
|
||||
"127.0.0.1"
|
||||
]
|
||||
}
|
||||
root-client-csr.json: |-
|
||||
{
|
||||
"CN": "root",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"names": [
|
||||
{
|
||||
"O": "system:masters"
|
||||
}
|
||||
]
|
||||
}
|
||||
{{- end }}
|
||||
@@ -1,35 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-delete
|
||||
"helm.sh/hook-weight": "-5"
|
||||
"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"
|
||||
name: "{{ .Release.Name }}-etcd-teardown"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: "{{ .Release.Name }}"
|
||||
spec:
|
||||
serviceAccountName: {{ include "etcd.serviceAccountName" . }}
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: kubectl
|
||||
image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }}
|
||||
command:
|
||||
- kubectl
|
||||
- --namespace={{ .Release.Namespace }}
|
||||
- delete
|
||||
- secret
|
||||
- --ignore-not-found=true
|
||||
- {{ include "etcd.caSecretName" . }}
|
||||
- {{ include "etcd.clientSecretName" . }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,74 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": post-install
|
||||
"helm.sh/hook-weight": "-5"
|
||||
"helm.sh/hook-delete-policy": "hook-succeeded,hook-failed"
|
||||
name: "{{ .Release.Name }}-etcd-setup"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: "{{ .Release.Name }}"
|
||||
spec:
|
||||
serviceAccountName: {{ include "etcd.serviceAccountName" . }}
|
||||
restartPolicy: Never
|
||||
initContainers:
|
||||
- name: kubectl
|
||||
image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |-
|
||||
kubectl --namespace={{ .Release.Namespace }} rollout status sts/etcd --timeout=300s
|
||||
containers:
|
||||
- command:
|
||||
- bash
|
||||
- -c
|
||||
- |-
|
||||
etcdctl member list -w table
|
||||
if etcdctl user get root &>/dev/null; then
|
||||
echo "User already exists, nothing to do"
|
||||
else
|
||||
etcdctl user add --no-password=true root &&
|
||||
etcdctl role add root &&
|
||||
etcdctl user grant-role root root &&
|
||||
etcdctl auth enable
|
||||
fi
|
||||
env:
|
||||
- name: ETCDCTL_ENDPOINTS
|
||||
value: https://etcd-0.{{ include "etcd.serviceName" . }}.{{ .Release.Namespace }}.svc.cluster.local:2379
|
||||
- name: ETCDCTL_CACERT
|
||||
value: /opt/certs/ca/ca.crt
|
||||
- name: ETCDCTL_CERT
|
||||
value: /opt/certs/root-certs/tls.crt
|
||||
- name: ETCDCTL_KEY
|
||||
value: /opt/certs/root-certs/tls.key
|
||||
image: quay.io/coreos/etcd:v3.5.1
|
||||
imagePullPolicy: Always
|
||||
name: etcd-client
|
||||
volumeMounts:
|
||||
- name: root-certs
|
||||
mountPath: /opt/certs/root-certs
|
||||
- name: certs
|
||||
mountPath: /opt/certs/ca
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
volumes:
|
||||
- name: root-certs
|
||||
secret:
|
||||
secretName: {{ include "etcd.clientSecretName" . }}
|
||||
- name: certs
|
||||
secret:
|
||||
secretName: {{ include "etcd.caSecretName" . }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,72 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install
|
||||
"helm.sh/hook-weight": "-5"
|
||||
"helm.sh/hook-delete-policy": "hook-succeeded"
|
||||
name: "{{ .Release.Name }}-etcd-certs"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
name: "{{ .Release.Name }}"
|
||||
spec:
|
||||
serviceAccountName: {{ include "etcd.serviceAccountName" . }}
|
||||
restartPolicy: Never
|
||||
initContainers:
|
||||
- name: cfssl
|
||||
image: "{{ .Values.cfssl.image.repository }}:{{ .Values.cfssl.image.tag }}"
|
||||
command:
|
||||
- bash
|
||||
- -c
|
||||
- |-
|
||||
cfssl gencert -initca /csr/ca-csr.json | cfssljson -bare /certs/ca &&
|
||||
mv /certs/ca.pem /certs/ca.crt && mv /certs/ca-key.pem /certs/ca.key &&
|
||||
cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=peer-authentication /csr/peer-csr.json | cfssljson -bare /certs/peer &&
|
||||
cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=peer-authentication /csr/server-csr.json | cfssljson -bare /certs/server &&
|
||||
cfssl gencert -ca=/certs/ca.crt -ca-key=/certs/ca.key -config=/csr/config.json -profile=client-authentication /csr/root-client-csr.json | cfssljson -bare /certs/root-client
|
||||
volumeMounts:
|
||||
- mountPath: /certs
|
||||
name: certs
|
||||
- mountPath: /csr
|
||||
name: csr
|
||||
containers:
|
||||
- name: kubectl
|
||||
image: {{ printf "clastix/kubectl:%s" (include "etcd.jobsTagKubeVersion" .) }}
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
if kubectl get secret {{ include "etcd.caSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then
|
||||
echo "Secret {{ include "etcd.caSecretName" . }} already exists"
|
||||
else
|
||||
echo "Creating secret {{ include "etcd.caSecretName" . }}"
|
||||
kubectl --namespace={{ .Release.Namespace }} create secret generic {{ include "etcd.caSecretName" . }} --from-file=/certs/ca.crt --from-file=/certs/ca.key --from-file=/certs/peer-key.pem --from-file=/certs/peer.pem --from-file=/certs/server-key.pem --from-file=/certs/server.pem
|
||||
fi
|
||||
if kubectl get secret {{ include "etcd.clientSecretName" . }} --namespace={{ .Release.Namespace }} &>/dev/null; then
|
||||
echo "Secret {{ include "etcd.clientSecretName" . }} already exists"
|
||||
else
|
||||
echo "Creating secret {{ include "etcd.clientSecretName" . }}"
|
||||
kubectl --namespace={{ .Release.Namespace }} create secret tls {{ include "etcd.clientSecretName" . }} --key=/certs/root-client-key.pem --cert=/certs/root-client.pem
|
||||
fi
|
||||
volumeMounts:
|
||||
- mountPath: /certs
|
||||
name: certs
|
||||
securityContext:
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
volumes:
|
||||
- name: csr
|
||||
configMap:
|
||||
name: {{ include "etcd.csrConfigMapName" . }}
|
||||
- name: certs
|
||||
emptyDir: {}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,56 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
name: etcd-gen-certs-role
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install
|
||||
"helm.sh/hook-weight": "-5"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- delete
|
||||
resourceNames:
|
||||
- {{ include "etcd.caSecretName" . }}
|
||||
- {{ include "etcd.clientSecretName" . }}
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- statefulsets
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
name: etcd-gen-certs-rolebiding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install
|
||||
"helm.sh/hook-weight": "-5"
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: etcd-gen-certs-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "etcd.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
@@ -1,12 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
name: {{ include "etcd.serviceAccountName" . }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install
|
||||
"helm.sh/hook-weight": "-5"
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- end }}
|
||||
@@ -1,18 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
name: {{ include "etcd.serviceName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
clusterIP: None
|
||||
ports:
|
||||
- port: {{ .Values.etcd.port }}
|
||||
name: client
|
||||
- port: {{ .Values.etcd.peerApiPort }}
|
||||
name: peer
|
||||
selector:
|
||||
{{- include "etcd.selectorLabels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -1,101 +0,0 @@
|
||||
{{- if .Values.etcd.deploy }}
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "etcd.labels" . | nindent 4 }}
|
||||
name: {{ include "etcd.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
serviceName: {{ include "etcd.serviceName" . }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "etcd.selectorLabels" . | nindent 6 }}
|
||||
replicas: 3
|
||||
template:
|
||||
metadata:
|
||||
name: etcd
|
||||
labels:
|
||||
{{- include "etcd.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
volumes:
|
||||
- name: certs
|
||||
secret:
|
||||
secretName: {{ include "etcd.caSecretName" . }}
|
||||
{{- with .Values.etcd.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: etcd
|
||||
image: {{ .Values.etcd.image.repository }}:{{ .Values.etcd.image.tag | default "v3.5.4" }}
|
||||
imagePullPolicy: {{ .Values.etcd.image.pullPolicy }}
|
||||
ports:
|
||||
- containerPort: 2379
|
||||
name: client
|
||||
- containerPort: 2380
|
||||
name: peer
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/run/etcd
|
||||
- name: certs
|
||||
mountPath: /etc/etcd/pki
|
||||
command:
|
||||
- etcd
|
||||
- --data-dir=/var/run/etcd
|
||||
- --name=$(POD_NAME)
|
||||
- --initial-cluster-state=new
|
||||
- --initial-cluster={{ include "etcd.initialCluster" . }}
|
||||
- --initial-advertise-peer-urls=https://$(POD_NAME).etcd.$(POD_NAMESPACE).svc.cluster.local:2380
|
||||
- --advertise-client-urls=https://$(POD_NAME).etcd.$(POD_NAMESPACE).svc.cluster.local:2379
|
||||
- --initial-cluster-token=kamaji
|
||||
- --listen-client-urls=https://0.0.0.0:2379
|
||||
- --listen-metrics-urls=http://0.0.0.0:2381
|
||||
- --listen-peer-urls=https://0.0.0.0:2380
|
||||
- --client-cert-auth=true
|
||||
- --peer-client-cert-auth=true
|
||||
- --trusted-ca-file=/etc/etcd/pki/ca.crt
|
||||
- --cert-file=/etc/etcd/pki/server.pem
|
||||
- --key-file=/etc/etcd/pki/server-key.pem
|
||||
- --peer-trusted-ca-file=/etc/etcd/pki/ca.crt
|
||||
- --peer-cert-file=/etc/etcd/pki/peer.pem
|
||||
- --peer-key-file=/etc/etcd/pki/peer-key.pem
|
||||
- --auto-compaction-mode=periodic
|
||||
- --auto-compaction-retention=5m
|
||||
- --snapshot-count=10000
|
||||
- --quota-backend-bytes=8589934592
|
||||
- --v=8
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
{{- with .Values.etcd.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.etcd.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
{{- with .Values.etcd.persistence.customAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
storageClassName: {{ .Values.etcd.persistence.storageClassName }}
|
||||
accessModes:
|
||||
{{- range .Values.etcd.persistence.accessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.etcd.persistence.size }}
|
||||
{{- end }}
|
||||
@@ -8,6 +8,27 @@ metadata:
|
||||
{{- include "kamaji.labels" $data | nindent 4 }}
|
||||
name: kamaji-validating-webhook-configuration
|
||||
webhooks:
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: {{ include "kamaji.webhookServiceName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
path: /telemetry
|
||||
failurePolicy: Ignore
|
||||
name: telemetry.kamaji.clastix.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- kamaji.clastix.io
|
||||
apiVersions:
|
||||
- v1alpha1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
- DELETE
|
||||
resources:
|
||||
- tenantcontrolplanes
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
|
||||
@@ -15,74 +15,10 @@ image:
|
||||
# -- A list of extra arguments to add to the kamaji controller default ones
|
||||
extraArgs: []
|
||||
|
||||
|
||||
serviceMonitor:
|
||||
# -- Toggle the ServiceMonitor true if you have Prometheus Operator installed and configured
|
||||
enabled: false
|
||||
|
||||
etcd:
|
||||
# -- Install an etcd with enabled multi-tenancy along with Kamaji
|
||||
deploy: true
|
||||
|
||||
# -- The peer API port which servers are listening to.
|
||||
peerApiPort: 2380
|
||||
|
||||
# -- The client request port.
|
||||
port: 2379
|
||||
|
||||
# -- Install specific etcd image
|
||||
image:
|
||||
repository: quay.io/coreos/etcd
|
||||
tag: "v3.5.6"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# -- The livenessProbe for the etcd container
|
||||
livenessProbe:
|
||||
failureThreshold: 8
|
||||
httpGet:
|
||||
path: /health?serializable=true
|
||||
port: 2381
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 15
|
||||
|
||||
serviceAccount:
|
||||
# -- Create a ServiceAccount, required to install and provision the etcd backing storage (default: true)
|
||||
create: true
|
||||
# -- Define the ServiceAccount name to use during the setup and provision of the etcd backing storage (default: "")
|
||||
name: ""
|
||||
persistence:
|
||||
size: 10Gi
|
||||
storageClassName: ""
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
# -- The custom annotations to add to the PVC
|
||||
customAnnotations: {}
|
||||
# volumeType: local
|
||||
|
||||
# -- (array) Kubernetes affinity rules to apply to Kamaji etcd pods
|
||||
tolerations: []
|
||||
|
||||
overrides:
|
||||
caSecret:
|
||||
# -- Name of the secret which contains CA's certificate and private key. (default: "etcd-certs")
|
||||
name: etcd-certs
|
||||
# -- Namespace of the secret which contains CA's certificate and private key. (default: "kamaji-system")
|
||||
namespace: kamaji-system
|
||||
clientSecret:
|
||||
# -- Name of the secret which contains ETCD client certificates. (default: "root-client-certs")
|
||||
name: root-client-certs
|
||||
# -- Name of the namespace where the secret which contains ETCD client certificates is. (default: "kamaji-system")
|
||||
namespace: kamaji-system
|
||||
# -- (map) Dictionary of the endpoints for the etcd cluster's members, key is the name of the etcd server. Don't define the protocol (TLS is automatically inflected), or any port, inflected from .etcd.peerApiPort value.
|
||||
endpoints:
|
||||
etcd-0: etcd-0.etcd.kamaji-system.svc.cluster.local
|
||||
etcd-1: etcd-1.etcd.kamaji-system.svc.cluster.local
|
||||
etcd-2: etcd-2.etcd.kamaji-system.svc.cluster.local
|
||||
# -- ETCD Compaction interval (e.g. "5m0s"). (default: "0" (disabled))
|
||||
compactionInterval: 0
|
||||
|
||||
# -- The address the probe endpoint binds to. (default ":8081")
|
||||
healthProbeBindAddress: ":8081"
|
||||
|
||||
@@ -102,7 +38,7 @@ readinessProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
||||
# -- (string) The address the metric endpoint binds to. (default ":8080")
|
||||
# -- The address the metric endpoint binds to. (default ":8080")
|
||||
metricsBindAddress: ":8080"
|
||||
|
||||
imagePullSecrets: []
|
||||
@@ -156,67 +92,20 @@ affinity: {}
|
||||
temporaryDirectoryPath: "/tmp/kamaji"
|
||||
|
||||
loggingDevel:
|
||||
# -- (string) Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false)
|
||||
# -- Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default false)
|
||||
enable: false
|
||||
|
||||
datastore:
|
||||
# -- (bool) Enable the Kamaji Datastore creation (default=true)
|
||||
enabled: true
|
||||
# -- (string) The Datastore name override, if empty and enabled=true defaults to `default`, if enabled=false, this is the name of the Datastore to connect to.
|
||||
nameOverride:
|
||||
# -- (string) The Kamaji Datastore driver, supported: etcd, MySQL, PostgreSQL (defaults=etcd).
|
||||
driver: etcd
|
||||
# -- (array) List of endpoints of the selected Datastore. When letting the Chart install the etcd datastore, this field is populated automatically.
|
||||
endpoints: []
|
||||
basicAuth:
|
||||
usernameSecret:
|
||||
# -- The name of the Secret containing the username used to connect to the relational database.
|
||||
name:
|
||||
# -- The namespace of the Secret containing the username used to connect to the relational database.
|
||||
namespace:
|
||||
# -- The Secret key where the data is stored.
|
||||
keyPath:
|
||||
passwordSecret:
|
||||
# -- The name of the Secret containing the password used to connect to the relational database.
|
||||
name:
|
||||
# -- The namespace of the Secret containing the password used to connect to the relational database.
|
||||
namespace:
|
||||
# -- The Secret key where the data is stored.
|
||||
keyPath:
|
||||
tlsConfig:
|
||||
enabled: true
|
||||
certificateAuthority:
|
||||
certificate:
|
||||
# -- Name of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
name:
|
||||
# -- Namespace of the Secret containing the CA required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
namespace:
|
||||
# -- Key of the Secret which contains the content of the certificate.
|
||||
keyPath:
|
||||
privateKey:
|
||||
# -- Name of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
name:
|
||||
# -- Namespace of the Secret containing the CA private key required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
namespace:
|
||||
# -- Key of the Secret which contains the content of the private key.
|
||||
keyPath:
|
||||
clientCertificate:
|
||||
certificate:
|
||||
# -- Name of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
name:
|
||||
# -- Namespace of the Secret containing the client certificate required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
namespace:
|
||||
# -- Key of the Secret which contains the content of the certificate.
|
||||
keyPath:
|
||||
privateKey:
|
||||
# -- Name of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
name:
|
||||
# -- Namespace of the Secret containing the client certificate private key required to establish the mandatory SSL/TLS connection to the datastore.
|
||||
namespace:
|
||||
# -- Key of the Secret which contains the content of the private key.
|
||||
keyPath:
|
||||
# -- Specify the default DataStore name for the Kamaji instance.
|
||||
defaultDatastoreName: default
|
||||
|
||||
cfssl:
|
||||
image:
|
||||
repository: cfssl/cfssl
|
||||
tag: latest
|
||||
kamaji-etcd:
|
||||
deploy: true
|
||||
fullnameOverride: kamaji-etcd
|
||||
datastore:
|
||||
enabled: true
|
||||
name: default
|
||||
|
||||
# -- Disable the analytics traces collection
|
||||
telemetry:
|
||||
disabled: false
|
||||
|
||||
@@ -7,10 +7,12 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
goRuntime "runtime"
|
||||
"time"
|
||||
|
||||
telemetryclient "github.com/clastix/kamaji-telemetry/pkg/client"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -53,6 +55,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
webhookCABundle []byte
|
||||
migrateJobImage string
|
||||
maxConcurrentReconciles int
|
||||
disableTelemetry bool
|
||||
|
||||
webhookCAPath string
|
||||
)
|
||||
@@ -95,8 +98,14 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
setupLog.Info(fmt.Sprintf("Build date: %s", internal.BuildTime))
|
||||
setupLog.Info(fmt.Sprintf("Go Version: %s", goRuntime.Version()))
|
||||
setupLog.Info(fmt.Sprintf("Go OS/Arch: %s/%s", goRuntime.GOOS, goRuntime.GOARCH))
|
||||
setupLog.Info(fmt.Sprintf("Telemetry enabled: %t", !disableTelemetry))
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
telemetryClient := telemetryclient.New(http.Client{Timeout: 5 * time.Second}, "https://telemetry.clastix.io")
|
||||
if disableTelemetry {
|
||||
telemetryClient = telemetryclient.NewNewOp()
|
||||
}
|
||||
|
||||
ctrlOpts := ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Metrics: metricsserver.Options{
|
||||
BindAddress: metricsBindAddress,
|
||||
@@ -107,13 +116,15 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
HealthProbeBindAddress: healthProbeBindAddress,
|
||||
LeaderElection: leaderElect,
|
||||
LeaderElectionNamespace: managerNamespace,
|
||||
LeaderElectionID: "799b98bc.clastix.io",
|
||||
LeaderElectionID: "kamaji.clastix.io",
|
||||
NewCache: func(config *rest.Config, opts cache.Options) (cache.Cache, error) {
|
||||
opts.SyncPeriod = &cacheResyncPeriod
|
||||
|
||||
return cache.New(config, opts)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrlOpts)
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to start manager")
|
||||
|
||||
@@ -152,6 +163,29 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
k8sVersion, versionErr := cmdutils.KubernetesVersion(mgr.GetConfig())
|
||||
if versionErr != nil {
|
||||
setupLog.Error(err, "unable to get kubernetes version")
|
||||
|
||||
k8sVersion = "Unknown"
|
||||
}
|
||||
|
||||
if !disableTelemetry {
|
||||
err = mgr.Add(&controllers.TelemetryController{
|
||||
Client: mgr.GetClient(),
|
||||
KubernetesVersion: k8sVersion,
|
||||
KamajiVersion: internal.GitTag,
|
||||
TelemetryClient: telemetryClient,
|
||||
LeaderElectionNamespace: ctrlOpts.LeaderElectionNamespace,
|
||||
LeaderElectionID: ctrlOpts.LeaderElectionID,
|
||||
})
|
||||
if err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "TelemetryController")
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = (&controllers.CertificateLifecycle{Channel: certChannel}).SetupWithManager(mgr); err != nil {
|
||||
setupLog.Error(err, "unable to create controller", "controller", "CertificateLifecycle")
|
||||
|
||||
@@ -196,6 +230,14 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
},
|
||||
handlers.TenantControlPlaneServiceCIDR{},
|
||||
},
|
||||
routes.TenantControlPlaneTelemetry{}: {
|
||||
handlers.TenantControlPlaneTelemetry{
|
||||
Enabled: !disableTelemetry,
|
||||
TelemetryClient: telemetryClient,
|
||||
KamajiVersion: internal.GitTag,
|
||||
KubernetesVersion: k8sVersion,
|
||||
},
|
||||
},
|
||||
routes.DataStoreValidate{}: {
|
||||
handlers.DataStoreValidation{Client: mgr.GetClient()},
|
||||
},
|
||||
@@ -255,7 +297,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
cmd.Flags().StringVar(&healthProbeBindAddress, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||
cmd.Flags().BoolVar(&leaderElect, "leader-elect", true, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
|
||||
cmd.Flags().StringVar(&tmpDirectory, "tmp-directory", "/tmp/kamaji", "Directory which will be used to work with temporary files.")
|
||||
cmd.Flags().StringVar(&kineImage, "kine-image", "rancher/kine:v0.9.2-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(&kineImage, "kine-image", "rancher/kine:v0.11.10-amd64", "Container image along with tag to use for the Kine sidecar container (used only if etcd-storage-type is set to one of kine strategies).")
|
||||
cmd.Flags().StringVar(&datastore, "datastore", "etcd", "The default DataStore that should be used by Kamaji to setup the required storage.")
|
||||
cmd.Flags().StringVar(&migrateJobImage, "migrate-image", fmt.Sprintf("clastix/kamaji:%s", internal.GitTag), "Specify the container image to launch when a TenantControlPlane is migrated to a new datastore.")
|
||||
cmd.Flags().IntVar(&maxConcurrentReconciles, "max-concurrent-tcp-reconciles", 1, "Specify the number of workers for the Tenant Control Plane controller (beware of CPU consumption)")
|
||||
@@ -265,6 +307,7 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
cmd.Flags().StringVar(&webhookCAPath, "webhook-ca-path", "/tmp/k8s-webhook-server/serving-certs/ca.crt", "Path to the Manager webhook server CA, required for the TenantControlPlane migration jobs.")
|
||||
cmd.Flags().DurationVar(&controllerReconcileTimeout, "controller-reconcile-timeout", 30*time.Second, "The reconciliation request timeout before the controller withdraw the external resource calls, such as dealing with the Datastore, or the Tenant Control Plane API endpoint.")
|
||||
cmd.Flags().DurationVar(&cacheResyncPeriod, "cache-resync-period", 10*time.Hour, "The controller-runtime.Manager cache resync period.")
|
||||
cmd.Flags().BoolVar(&disableTelemetry, "disable-telemetry", false, "Disable the analytics traces collection.")
|
||||
|
||||
cobra.OnInitialize(func() {
|
||||
viper.AutomaticEnv()
|
||||
|
||||
24
cmd/utils/k8s_version.go
Normal file
24
cmd/utils/k8s_version.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
func KubernetesVersion(config *rest.Config) (string, error) {
|
||||
cs, csErr := kubernetes.NewForConfig(config)
|
||||
if csErr != nil {
|
||||
return "", errors.Wrap(csErr, "cannot create kubernetes clientset")
|
||||
}
|
||||
|
||||
sv, svErr := cs.ServerVersion()
|
||||
if svErr != nil {
|
||||
return "", errors.Wrap(svErr, "cannot get Kubernetes version")
|
||||
}
|
||||
|
||||
return sv.GitVersion, nil
|
||||
}
|
||||
@@ -95,7 +95,7 @@ spec:
|
||||
agent:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
version: v0.0.32
|
||||
version: v0.28.6
|
||||
properties:
|
||||
extraArgs:
|
||||
description: |-
|
||||
@@ -156,7 +156,7 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
version:
|
||||
default: v0.0.32
|
||||
default: v0.28.6
|
||||
description: Version for Konnectivity agent.
|
||||
type: string
|
||||
type: object
|
||||
@@ -164,7 +164,7 @@ spec:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-server
|
||||
port: 8132
|
||||
version: v0.0.32
|
||||
version: v0.28.6
|
||||
properties:
|
||||
extraArgs:
|
||||
description: |-
|
||||
@@ -243,7 +243,7 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
default: v0.0.32
|
||||
default: v0.28.6
|
||||
description: Container image version of the Konnectivity
|
||||
server.
|
||||
type: string
|
||||
|
||||
@@ -394,7 +394,7 @@ spec:
|
||||
agent:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
version: v0.0.32
|
||||
version: v0.28.6
|
||||
properties:
|
||||
extraArgs:
|
||||
description: |-
|
||||
@@ -454,7 +454,7 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
version:
|
||||
default: v0.0.32
|
||||
default: v0.28.6
|
||||
description: Version for Konnectivity agent.
|
||||
type: string
|
||||
type: object
|
||||
@@ -462,7 +462,7 @@ spec:
|
||||
default:
|
||||
image: registry.k8s.io/kas-network-proxy/proxy-server
|
||||
port: 8132
|
||||
version: v0.0.32
|
||||
version: v0.28.6
|
||||
properties:
|
||||
extraArgs:
|
||||
description: |-
|
||||
@@ -537,7 +537,7 @@ spec:
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
default: v0.0.32
|
||||
default: v0.28.6
|
||||
description: Container image version of the Konnectivity server.
|
||||
type: string
|
||||
required:
|
||||
@@ -8016,7 +8016,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.serviceAccountName
|
||||
image: clastix/kamaji:v0.6.1
|
||||
image: clastix/kamaji:v1.0.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -8208,6 +8208,27 @@ metadata:
|
||||
cluster.x-k8s.io/provider: kamaji-core
|
||||
name: kamaji-validating-webhook-configuration
|
||||
webhooks:
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: kamaji-webhook-service
|
||||
namespace: kamaji-system
|
||||
path: /telemetry
|
||||
failurePolicy: Ignore
|
||||
name: telemetry.kamaji.clastix.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- kamaji.clastix.io
|
||||
apiVersions:
|
||||
- v1alpha1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
- DELETE
|
||||
resources:
|
||||
- tenantcontrolplanes
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
|
||||
@@ -13,4 +13,4 @@ kind: Kustomization
|
||||
images:
|
||||
- name: controller
|
||||
newName: clastix/kamaji
|
||||
newTag: v0.6.1
|
||||
newTag: v1.0.0
|
||||
|
||||
@@ -30,6 +30,27 @@ kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: validating-webhook-configuration
|
||||
webhooks:
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
service:
|
||||
name: webhook-service
|
||||
namespace: system
|
||||
path: /telemetry
|
||||
failurePolicy: Ignore
|
||||
name: telemetry.kamaji.clastix.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- kamaji.clastix.io
|
||||
apiVersions:
|
||||
- v1alpha1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
- DELETE
|
||||
resources:
|
||||
- tenantcontrolplanes
|
||||
sideEffects: None
|
||||
- admissionReviewVersions:
|
||||
- v1
|
||||
clientConfig:
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
@@ -98,7 +97,7 @@ func (r *DataStore) SetupWithManager(mgr controllerruntime.Manager) error {
|
||||
For(&kamajiv1alpha1.DataStore{}, builder.WithPredicates(
|
||||
predicate.ResourceVersionChangedPredicate{},
|
||||
)).
|
||||
WatchesRawSource(source.Kind(mgr.GetCache(), &kamajiv1alpha1.TenantControlPlane{}), handler.Funcs{
|
||||
Watches(&kamajiv1alpha1.TenantControlPlane{}, handler.Funcs{
|
||||
CreateFunc: func(_ context.Context, createEvent event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) {
|
||||
enqueueFn(createEvent.Object.(*kamajiv1alpha1.TenantControlPlane), limitingInterface)
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ func (c *CoreDNS) SetupWithManager(mgr manager.Manager) error {
|
||||
For(&rbacv1.ClusterRoleBinding{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
|
||||
return object.GetName() == kubeadm.CoreDNSClusterRoleBindingName
|
||||
}))).
|
||||
WatchesRawSource(&source.Channel{Source: c.TriggerChannel}, &handler.EnqueueRequestForObject{}).
|
||||
WatchesRawSource(source.Channel(c.TriggerChannel, &handler.EnqueueRequestForObject{})).
|
||||
Owns(&rbacv1.ClusterRole{}).
|
||||
Owns(&corev1.ServiceAccount{}).
|
||||
Owns(&corev1.Service{}).
|
||||
|
||||
@@ -80,7 +80,7 @@ func (k *KonnectivityAgent) SetupWithManager(mgr manager.Manager) error {
|
||||
For(&appsv1.DaemonSet{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
|
||||
return object.GetName() == konnectivity.AgentName && object.GetNamespace() == konnectivity.AgentNamespace
|
||||
}))).
|
||||
WatchesRawSource(source.Kind(mgr.GetCache(), &corev1.ServiceAccount{}), handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
|
||||
Watches(&corev1.ServiceAccount{}, handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
|
||||
if object.GetName() == konnectivity.AgentName && object.GetNamespace() == konnectivity.AgentNamespace {
|
||||
return []reconcile.Request{
|
||||
{
|
||||
@@ -94,7 +94,7 @@ func (k *KonnectivityAgent) SetupWithManager(mgr manager.Manager) error {
|
||||
|
||||
return nil
|
||||
})).
|
||||
WatchesRawSource(source.Kind(mgr.GetCache(), &v1.ClusterRoleBinding{}), handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
|
||||
Watches(&v1.ClusterRoleBinding{}, handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
|
||||
if object.GetName() == konnectivity.CertCommonName {
|
||||
return []reconcile.Request{
|
||||
{
|
||||
@@ -107,6 +107,6 @@ func (k *KonnectivityAgent) SetupWithManager(mgr manager.Manager) error {
|
||||
|
||||
return nil
|
||||
})).
|
||||
WatchesRawSource(&source.Channel{Source: k.TriggerChannel}, &handler.EnqueueRequestForObject{}).
|
||||
WatchesRawSource(source.Channel(k.TriggerChannel, &handler.EnqueueRequestForObject{})).
|
||||
Complete(k)
|
||||
}
|
||||
|
||||
@@ -67,6 +67,6 @@ func (k *KubeadmPhase) SetupWithManager(mgr manager.Manager) error {
|
||||
|
||||
return controllerruntime.NewControllerManagedBy(mgr).
|
||||
For(k.Phase.GetWatchedObject(), builder.WithPredicates(predicate.NewPredicateFuncs(k.Phase.GetPredicateFunc()))).
|
||||
WatchesRawSource(&source.Channel{Source: k.TriggerChannel}, &handler.EnqueueRequestForObject{}).
|
||||
WatchesRawSource(source.Channel(k.TriggerChannel, &handler.EnqueueRequestForObject{})).
|
||||
Complete(k)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func (k *KubeProxy) SetupWithManager(mgr manager.Manager) error {
|
||||
For(&rbacv1.ClusterRoleBinding{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
|
||||
return object.GetName() == kubeadm.KubeProxyClusterRoleBindingName
|
||||
}))).
|
||||
WatchesRawSource(&source.Channel{Source: k.TriggerChannel}, &handler.EnqueueRequestForObject{}).
|
||||
WatchesRawSource(source.Channel(k.TriggerChannel, &handler.EnqueueRequestForObject{})).
|
||||
Owns(&corev1.ServiceAccount{}).
|
||||
Owns(&rbacv1.Role{}).
|
||||
Owns(&rbacv1.RoleBinding{}).
|
||||
|
||||
@@ -187,7 +187,7 @@ func (m *Migrate) SetupWithManager(mgr manager.Manager) error {
|
||||
|
||||
return object.GetName() == vwc.GetName()
|
||||
}))).
|
||||
WatchesRawSource(&source.Channel{Source: m.TriggerChannel}, &handler.EnqueueRequestForObject{}).
|
||||
WatchesRawSource(source.Channel(m.TriggerChannel, &handler.EnqueueRequestForObject{})).
|
||||
Complete(m)
|
||||
}
|
||||
|
||||
|
||||
@@ -302,7 +302,7 @@ func (m *Manager) SetupWithManager(mgr manager.Manager) error {
|
||||
m.sootMap = make(map[string]sootItem)
|
||||
|
||||
return controllerruntime.NewControllerManagedBy(mgr).
|
||||
WatchesRawSource(&source.Channel{Source: m.sootManagerErrChan}, &handler.EnqueueRequestForObject{}).
|
||||
WatchesRawSource(source.Channel(m.sootManagerErrChan, &handler.EnqueueRequestForObject{})).
|
||||
For(&kamajiv1alpha1.TenantControlPlane{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
|
||||
obj := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
// status is required to understand if we have to start or stop the soot manager
|
||||
|
||||
120
controllers/telemetry_controller.go
Normal file
120
controllers/telemetry_controller.go
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/clastix/kamaji-telemetry/api"
|
||||
telemetry "github.com/clastix/kamaji-telemetry/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
type TelemetryController struct {
|
||||
Client client.Client
|
||||
TelemetryClient telemetry.Client
|
||||
LeaderElectionNamespace string
|
||||
LeaderElectionID string
|
||||
KamajiVersion string
|
||||
KubernetesVersion string
|
||||
}
|
||||
|
||||
func (m *TelemetryController) retrieveControllerUID(ctx context.Context) (string, error) {
|
||||
var defaultSvc corev1.Service
|
||||
if err := m.Client.Get(ctx, types.NamespacedName{Name: "kubernetes", Namespace: "default"}, &defaultSvc); err != nil {
|
||||
return "", errors.Wrap(err, "cannot start the telemetry controller")
|
||||
}
|
||||
|
||||
return string(defaultSvc.UID), nil
|
||||
}
|
||||
|
||||
func (m *TelemetryController) Start(ctx context.Context) error {
|
||||
logger := log.FromContext(ctx)
|
||||
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
uid, err := m.retrieveControllerUID(ctx)
|
||||
if err != nil {
|
||||
logger.Error(err, "cannot retrieve controller UID")
|
||||
|
||||
return err
|
||||
}
|
||||
// First run to avoid waiting 5 minutes
|
||||
go m.collectStats(ctx, uid)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
go m.collectStats(ctx, uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *TelemetryController) collectStats(ctx context.Context, uid string) {
|
||||
logger := log.FromContext(ctx)
|
||||
|
||||
stats := api.Stats{
|
||||
UUID: uid,
|
||||
KamajiVersion: m.KamajiVersion,
|
||||
KubernetesVersion: m.KubernetesVersion,
|
||||
TenantControlPlanes: api.TenantControlPlane{},
|
||||
Datastores: api.Datastores{},
|
||||
}
|
||||
|
||||
var tcpList kamajiv1alpha1.TenantControlPlaneList
|
||||
if err := m.Client.List(ctx, &tcpList); err != nil {
|
||||
logger.Error(err, "cannot list TenantControlPlane")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
for _, tcp := range tcpList.Items {
|
||||
switch {
|
||||
case tcp.Spec.ControlPlane.Deployment.Replicas == nil || *tcp.Spec.ControlPlane.Deployment.Replicas == 0:
|
||||
stats.TenantControlPlanes.Sleeping++
|
||||
case tcp.Status.Kubernetes.Version.Status != nil && *tcp.Status.Kubernetes.Version.Status == kamajiv1alpha1.VersionNotReady:
|
||||
stats.TenantControlPlanes.NotReady++
|
||||
case tcp.Status.Kubernetes.Version.Status != nil && *tcp.Status.Kubernetes.Version.Status == kamajiv1alpha1.VersionUpgrading:
|
||||
stats.TenantControlPlanes.Upgrading++
|
||||
default:
|
||||
stats.TenantControlPlanes.Running++
|
||||
}
|
||||
}
|
||||
|
||||
var datastoreList kamajiv1alpha1.DataStoreList
|
||||
if err := m.Client.List(ctx, &datastoreList); err != nil {
|
||||
logger.Error(err, "cannot list DataStores")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
for _, ds := range datastoreList.Items {
|
||||
switch ds.Spec.Driver {
|
||||
case kamajiv1alpha1.EtcdDriver:
|
||||
stats.Datastores.Etcd.ShardCount++
|
||||
stats.Datastores.Etcd.UsedByCount += len(ds.Status.UsedBy)
|
||||
case kamajiv1alpha1.KinePostgreSQLDriver:
|
||||
stats.Datastores.PostgreSQL.ShardCount++
|
||||
stats.Datastores.PostgreSQL.UsedByCount += len(ds.Status.UsedBy)
|
||||
case kamajiv1alpha1.KineMySQLDriver:
|
||||
stats.Datastores.MySQL.ShardCount++
|
||||
stats.Datastores.MySQL.UsedByCount += len(ds.Status.UsedBy)
|
||||
case kamajiv1alpha1.KineNatsDriver:
|
||||
stats.Datastores.NATS.ShardCount++
|
||||
stats.Datastores.NATS.UsedByCount += len(ds.Status.UsedBy)
|
||||
}
|
||||
}
|
||||
|
||||
m.TelemetryClient.PushStats(ctx, stats)
|
||||
}
|
||||
@@ -227,29 +227,29 @@ func (r *TenantControlPlaneReconciler) SetupWithManager(mgr ctrl.Manager) error
|
||||
r.clock = clock.RealClock{}
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
WatchesRawSource(&source.Channel{Source: r.CertificateChan}, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
|
||||
WatchesRawSource(source.Channel(r.CertificateChan, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
|
||||
limitingInterface.AddRateLimited(ctrl.Request{
|
||||
NamespacedName: k8stypes.NamespacedName{
|
||||
Namespace: genericEvent.Object.GetNamespace(),
|
||||
Name: genericEvent.Object.GetName(),
|
||||
},
|
||||
})
|
||||
}}).
|
||||
WatchesRawSource(&source.Channel{Source: r.TriggerChan}, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
|
||||
}})).
|
||||
WatchesRawSource(source.Channel(r.TriggerChan, handler.Funcs{GenericFunc: func(_ context.Context, genericEvent event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) {
|
||||
limitingInterface.AddRateLimited(ctrl.Request{
|
||||
NamespacedName: k8stypes.NamespacedName{
|
||||
Namespace: genericEvent.Object.GetNamespace(),
|
||||
Name: genericEvent.Object.GetName(),
|
||||
},
|
||||
})
|
||||
}}).
|
||||
}})).
|
||||
For(&kamajiv1alpha1.TenantControlPlane{}).
|
||||
Owns(&corev1.Secret{}).
|
||||
Owns(&corev1.ConfigMap{}).
|
||||
Owns(&appsv1.Deployment{}).
|
||||
Owns(&corev1.Service{}).
|
||||
Owns(&networkingv1.Ingress{}).
|
||||
WatchesRawSource(source.Kind(mgr.GetCache(), &batchv1.Job{}), handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
|
||||
Watches(&batchv1.Job{}, handler.EnqueueRequestsFromMapFunc(func(_ context.Context, object client.Object) []reconcile.Request {
|
||||
labels := object.GetLabels()
|
||||
|
||||
name, namespace := labels["tcp.kamaji.clastix.io/name"], labels["tcp.kamaji.clastix.io/namespace"]
|
||||
|
||||
@@ -44,7 +44,7 @@ spec:
|
||||
secretName: mysql-certs
|
||||
containers:
|
||||
- name: kine-tenant
|
||||
image: rancher/kine:v0.9.2-amd64
|
||||
image: rancher/kine:v0.11.10-amd64
|
||||
ports:
|
||||
- containerPort: 2379
|
||||
name: server
|
||||
|
||||
@@ -26,7 +26,7 @@ For example, with a PostgreSQL datastore installed:
|
||||
|
||||
```bash
|
||||
helm install kamaji charts/kamaji -n kamaji-system --create-namespace \
|
||||
--set etcd.deploy=false \
|
||||
--set kamaji-etcd.deploy=false \
|
||||
--set datastore.driver=PostgreSQL \
|
||||
--set datastore.endpoints[0]=postgres-default-rw.kamaji-system.svc:5432 \
|
||||
--set datastore.basicAuth.usernameSecret.name=postgres-default-superuser \
|
||||
|
||||
@@ -172,4 +172,25 @@ After a while, depending on the amount of data to migrate, the Tenant Control Pl
|
||||
> Please, note the datastore migration leaves the data on the default datastore, so you have to remove it manually.
|
||||
|
||||
## Post migration
|
||||
After migrating data to the new datastore, complete the migration procedure by restarting the `kubelet.service` on all the tenant worker nodes.
|
||||
After migrating data to the new datastore, complete the migration procedure by restarting the `kubelet.service` on all the tenant worker nodes.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Migration Job Image Version
|
||||
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
|
||||
--set extraArgs[0]=--migrate-image=custom/kamaji:version`
|
||||
```
|
||||
|
||||
### Handling Private Registry Images
|
||||
If the Kamaji controller images are stored in a private registry that requires authentication, the migration job will fail because it does not use any `ImagePullSecret` by default. You need to attach your registry secret to the `kamaji-controller-manager` service account, which is used by the migration job. You can do this with the following command:
|
||||
|
||||
```shell
|
||||
kubectl -n kamaji-system patch serviceaccount kamaji-controller-manager \
|
||||
-p '{"imagePullSecrets": [{"name": "myregistry-credentials"}]}'
|
||||
```
|
||||
|
||||
This command patches the kamaji-controller-manager service account to include your registry secret, allowing the migration job to pull images from the private registry successfully.
|
||||
|
||||
|
||||
@@ -13509,7 +13509,7 @@ Enables the Konnectivity addon in the Tenant Cluster, required if the worker nod
|
||||
<td>
|
||||
<br/>
|
||||
<br/>
|
||||
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-agent version:v0.0.32]<br/>
|
||||
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-agent version:v0.28.6]<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -13518,7 +13518,7 @@ Enables the Konnectivity addon in the Tenant Cluster, required if the worker nod
|
||||
<td>
|
||||
<br/>
|
||||
<br/>
|
||||
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-server port:8132 version:v0.0.32]<br/>
|
||||
<i>Default</i>: map[image:registry.k8s.io/kas-network-proxy/proxy-server port:8132 version:v0.28.6]<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -13575,7 +13575,7 @@ Can be customized to start the konnectivity-agent even if the nodes are not read
|
||||
<td>
|
||||
Version for Konnectivity agent.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: v0.0.32<br/>
|
||||
<i>Default</i>: v0.28.6<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -13704,7 +13704,7 @@ unxpected ways. Only modify if you know what you are doing.<br/>
|
||||
<td>
|
||||
Container image version of the Konnectivity server.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: v0.0.32<br/>
|
||||
<i>Default</i>: v0.28.6<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
|
||||
@@ -10,7 +10,7 @@ Available flags are the following:
|
||||
| `--health-probe-bind-address` | The address the probe endpoint binds to. | `:8081` |
|
||||
| `--leader-elect` | Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager. | `true` |
|
||||
| `--tmp-directory` | Directory which will be used to work with temporary files. | `/tmp/kamaji` |
|
||||
| `--kine-image` | 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). | `rancher/kine:v0.9.2-amd64` |
|
||||
| `--kine-image` | 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). | `rancher/kine:v0.11.10-amd64` |
|
||||
| `--datastore` | The default DataStore that should be used by Kamaji to setup the required storage. | `etcd` |
|
||||
| `--migrate-image` | Specify the container image to launch when a TenantControlPlane is migrated to a new datastore. | `migrate-image` |
|
||||
| `--max-concurrent-tcp-reconciles` | Specify the number of workers for the Tenant Control Plane controller (beware of CPU consumption). | `1` |
|
||||
|
||||
@@ -12,6 +12,8 @@ All the _“Tenant Clusters”_ built with Kamaji are CNCF conformant:
|
||||
- [v1.26](https://github.com/cncf/k8s-conformance/pull/2787)
|
||||
- [v1.27](https://github.com/cncf/k8s-conformance/pull/2786)
|
||||
- [v1.28](https://github.com/cncf/k8s-conformance/pull/2785)
|
||||
- [v1.29](https://github.com/cncf/k8s-conformance/pull/3273)
|
||||
- [v1.30](https://github.com/cncf/k8s-conformance/pull/3274)
|
||||
|
||||
<p align="left" style="padding: 6px 6px">
|
||||
<img src="https://raw.githubusercontent.com/cncf/artwork/master/projects/kubernetes/certified-kubernetes/versionless/color/certified-kubernetes-color.png" width="100" />
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
# Versioning
|
||||
# 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.
|
||||
|
||||
## Types of release artifacts
|
||||
|
||||
### 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 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.
|
||||
|
||||
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) organization does not no longer provide stable release artifacts. Stable Release artefacts are offered on a subscription basis by [CLASTIX](https://clastix.io), the main Kamaji project contributor.
|
||||
|
||||
In Kamaji, there are different components that might require independent versioning and support level:
|
||||
|
||||
| Kamaji | Management Cluster | Tenant Cluster |
|
||||
|--------|--------------------|----------------------|
|
||||
| v0.0 | v1.22+ | [v1.21.0 .. v1.23.5] |
|
||||
| v0.1 | v1.22+ | [v1.21.0 .. v1.25.0] |
|
||||
| v0.2 | v1.22+ | [v1.21.0 .. v1.27.0] |
|
||||
| v0.3.0 | v1.22+ | [v1.21.0 .. v1.27.0] |
|
||||
| v0.3.1 | v1.22+ | [v1.21.0 .. v1.27.3] |
|
||||
| v0.3.2 | v1.22+ | [v1.21.0 .. v1.27.3] |
|
||||
@@ -19,3 +33,4 @@ In Kamaji, there are different components that might require independent version
|
||||
| v0.4.2 | v1.22+ | [v1.21.0 .. v1.29.1] |
|
||||
| v0.5.0 | v1.22+ | [v1.21.0 .. v1.30.0] |
|
||||
| v0.6.0 | v1.22+ | [v1.21.0 .. v1.30.1] |
|
||||
| v1.0.0 | v1.22+ | [v1.21.0 .. v1.30.2] |
|
||||
49
docs/content/telemetry.md
Normal file
49
docs/content/telemetry.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Telemetry
|
||||
|
||||
This document outlines the telemetry feature within the Kamaji project, detailing the rationale behind data collection, the nature of the data collected, data handling practices, and instructions for opting out.
|
||||
|
||||
## Why We Collect Telemetry
|
||||
|
||||
The Kamaji project, being open source, benefits from insights into how it is used. These insights help the project maintainers make informed decisions regarding feature prioritization, test automation, and bug fixes. Without this data, decisions on feature deprecation and enhancements would be based on limited information, potentially hindering the project's evolution and maintainability. Our goal is to ensure Kamaji's development is driven by the needs of its community, and telemetry data plays a crucial role in achieving this.
|
||||
|
||||
## What We Collect and How
|
||||
|
||||
It's important to clarify that our interest lies in the usage patterns of Kamaji, not in personal information about its users. We collect data about Kamaji version and Tenant Control Planes.
|
||||
|
||||
### Telemetry Payload Example
|
||||
|
||||
Below is a simplified example of what a telemetry payload might look like:
|
||||
|
||||
```json
|
||||
// General status
|
||||
{"uuid": "56279633-3131-436b-b8f2-9008a49a2f12", "running": 1, "sleeping": 0, "not_ready": 0, "upgrading": 0, "kamaji_version": "v0.6.1", "kubernetes_version": "v1.27.3"}
|
||||
```
|
||||
|
||||
```json
|
||||
// Creating a TCP
|
||||
{"tcp_version": "v1.26.0", "kamaji_version": "v0.6.1", "kubernetes_version": "v1.27.3"}
|
||||
```
|
||||
|
||||
```json
|
||||
// Modifying a TCP (n.b.: version upgrade)
|
||||
{"kamaji_version": "v0.6.1", "new_tcp_version": "v1.27.0", "old_tcp_version": "v1.26.0", "kubernetes_version": "v1.27.3"}
|
||||
```
|
||||
|
||||
```json
|
||||
// Deleting a TCP
|
||||
{"status": "Ready", "tcp_version": "v1.27.0", "kamaji_version": "v0.6.1", "kubernetes_version": "v1.27.3"}
|
||||
```
|
||||
|
||||
Data is collected through a component within Kamaji, which periodically sends this information to our backend. The telemetry backend, managed by the Kamaji maintainers, ensures data is stored securely and access is strictly controlled.
|
||||
|
||||
## Telemetry Opt-Out
|
||||
We respect the privacy and autonomy of our users. If you prefer not to participate in telemetry, Kamaji provides an easy opt-out mechanism.
|
||||
|
||||
For Helm based deployments, include the `--set telemetry.disabled=true` flag when installing or upgrading Kamaji.
|
||||
|
||||
For manual deployments, set the flag `--disable-telemetry=true` int the Kamaji controller configuration to disable telemetry reporting.
|
||||
|
||||
To re-enable telemetry, simply reverse the opt-out process using the appropriate method for your deployment.
|
||||
|
||||
## Conclusion
|
||||
Telemetry in Kamaji is designed to foster a data-driven development process that aligns with the needs and preferences of our user community. Your participation helps us make Kamaji better for everyone.
|
||||
@@ -76,4 +76,5 @@ nav:
|
||||
- reference/conformance.md
|
||||
- reference/versioning.md
|
||||
- reference/api.md
|
||||
- 'Telemetry': telemetry.md
|
||||
- 'Contribute': contribute.md
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
@@ -73,9 +75,17 @@ var _ = Describe("starting a kind worker with kubeadm", func() {
|
||||
|
||||
workerContainer, err = testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: testcontainers.ContainerRequest{
|
||||
HostConfigModifier: func(config *container.HostConfig) {
|
||||
config.Mounts = []mount.Mount{
|
||||
{
|
||||
Type: mount.TypeBind,
|
||||
Source: "/lib/modules",
|
||||
Target: "/lib/modules",
|
||||
},
|
||||
}
|
||||
},
|
||||
Name: fmt.Sprintf("%s-worker-node", tcp.GetName()),
|
||||
Image: fmt.Sprintf("kindest/node:%s", tcp.Spec.Kubernetes.Version),
|
||||
Mounts: testcontainers.ContainerMounts{testcontainers.BindMount("/lib/modules", "/lib/modules")},
|
||||
Networks: []string{"kind"},
|
||||
Privileged: true,
|
||||
},
|
||||
@@ -135,7 +145,7 @@ var _ = Describe("starting a kind worker with kubeadm", func() {
|
||||
By("executing the command in the worker node", func() {
|
||||
cmds := append(strings.Split(strings.TrimSpace(joinCommandBuffer.String()), " "), "--ignore-preflight-errors", "SystemVerification")
|
||||
|
||||
exitCode, err := workerContainer.Exec(ctx, cmds)
|
||||
exitCode, _, err := workerContainer.Exec(ctx, cmds)
|
||||
Expect(exitCode).To(Equal(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
142
go.mod
142
go.mod
@@ -7,76 +7,83 @@ toolchain go1.22.1
|
||||
require (
|
||||
github.com/JamesStewy/go-mysqldump v0.2.2
|
||||
github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/go-logr/logr v1.4.1
|
||||
github.com/go-pg/pg/v10 v10.10.6
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/clastix/kamaji-telemetry v1.0.0
|
||||
github.com/docker/docker v27.1.1+incompatible
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/go-pg/pg/v10 v10.13.0
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/uuid v1.3.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.34.1
|
||||
github.com/onsi/ginkgo/v2 v2.17.1
|
||||
github.com/onsi/gomega v1.32.0
|
||||
github.com/nats-io/nats.go v1.36.0
|
||||
github.com/onsi/ginkgo/v2 v2.20.0
|
||||
github.com/onsi/gomega v1.34.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.10.1
|
||||
github.com/testcontainers/testcontainers-go v0.13.0
|
||||
go.etcd.io/etcd/api/v3 v3.5.10
|
||||
go.etcd.io/etcd/client/v3 v3.5.10
|
||||
go.uber.org/automaxprocs v1.5.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/testcontainers/testcontainers-go v0.32.0
|
||||
go.etcd.io/etcd/api/v3 v3.5.15
|
||||
go.etcd.io/etcd/client/v3 v3.5.15
|
||||
go.uber.org/automaxprocs v1.5.3
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||
k8s.io/api v0.30.2
|
||||
k8s.io/apimachinery v0.30.2
|
||||
k8s.io/apiserver v0.30.2
|
||||
k8s.io/client-go v0.30.2
|
||||
k8s.io/cluster-bootstrap v0.0.0
|
||||
k8s.io/klog/v2 v2.120.1
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kubelet v0.0.0
|
||||
k8s.io/kubernetes v1.30.2
|
||||
k8s.io/kubernetes v1.30.3
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
|
||||
sigs.k8s.io/controller-runtime v0.17.1-0.20240416095710-67b27f27e514
|
||||
sigs.k8s.io/controller-runtime v0.18.4
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/Microsoft/hcsshim v0.8.25 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/containerd/containerd v1.5.9 // indirect
|
||||
github.com/containerd/containerd v1.7.18 // indirect
|
||||
github.com/containerd/errdefs v0.1.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/coredns/caddy v1.1.1 // indirect
|
||||
github.com/coredns/corefile-migration v1.0.21 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/distribution/reference v0.5.0 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker v20.10.11+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/go-pg/zerochecker v0.2.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
@@ -88,13 +95,16 @@ require (
|
||||
github.com/klauspost/compress v1.17.8 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/lithammer/dedent v1.1.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/moby/sys/mount v0.2.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.6.2 // indirect
|
||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/user v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
@@ -103,50 +113,58 @@ require (
|
||||
github.com/nats-io/nkeys v0.4.7 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/opencontainers/runc v1.1.12 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // 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.18.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/spf13/afero v1.9.2 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||
github.com/vmihailenco/bufpool v0.1.11 // indirect
|
||||
github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect
|
||||
github.com/vmihailenco/tagparser v0.1.2 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
|
||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/crypto v0.22.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
|
||||
golang.org/x/mod v0.15.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/oauth2 v0.12.0 // indirect
|
||||
golang.org/x/sync v0.6.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/term v0.19.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.18.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
|
||||
google.golang.org/grpc v1.58.3 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
golang.org/x/crypto v0.26.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/oauth2 v0.18.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.23.0 // indirect
|
||||
golang.org/x/term v0.23.0 // indirect
|
||||
golang.org/x/text v0.17.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
|
||||
google.golang.org/grpc v1.62.1 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
@@ -157,7 +175,7 @@ require (
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
k8s.io/kube-proxy v0.0.0 // indirect
|
||||
k8s.io/system-validators v1.8.0 // indirect
|
||||
mellium.im/sasl v0.3.0 // indirect
|
||||
mellium.im/sasl v0.3.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
|
||||
@@ -23,7 +23,7 @@ type ConnectionEndpoint struct {
|
||||
}
|
||||
|
||||
func (r ConnectionEndpoint) String() string {
|
||||
return fmt.Sprintf("%s:%d", r.Host, r.Port)
|
||||
return net.JoinHostPort(r.Host, strconv.FormatInt(int64(r.Port), 10))
|
||||
}
|
||||
|
||||
type ConnectionConfig struct {
|
||||
|
||||
@@ -16,13 +16,6 @@ import (
|
||||
"github.com/clastix/kamaji/internal/datastore/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// rangeEnd is the key following the last key of the range.
|
||||
// If rangeEnd is ‘\0’, the range is all keys greater than or equal to the key argument
|
||||
// source: https://etcd.io/docs/v3.5/learning/api/
|
||||
rangeEnd = "\\0"
|
||||
)
|
||||
|
||||
func NewETCDConnection(config ConnectionConfig) (Connection, error) {
|
||||
endpoints := make([]string, 0, len(config.Endpoints))
|
||||
|
||||
@@ -68,7 +61,8 @@ func (e *EtcdClient) GrantPrivileges(ctx context.Context, user, dbName string) e
|
||||
|
||||
permission := etcdclient.PermissionType(authpb.READWRITE)
|
||||
key := e.buildKey(dbName)
|
||||
if _, err := e.Client.RoleGrantPermission(ctx, user, key, rangeEnd, permission); err != nil {
|
||||
|
||||
if _, err := e.Client.RoleGrantPermission(ctx, user, key, etcdclient.GetPrefixRangeEnd(key), permission); err != nil {
|
||||
return errors.NewGrantPrivilegesError(err)
|
||||
}
|
||||
|
||||
@@ -170,6 +164,13 @@ func (e *EtcdClient) Driver() string {
|
||||
return string(kamajiv1alpha1.EtcdDriver)
|
||||
}
|
||||
|
||||
// buildKey adds slashes to the beginning and end of the key. This ensures that the range
|
||||
// end for etcd RBAC is calculated using the entire key prefix, not only the key name. If
|
||||
// the range end was calculated e.g. for `/cp-a`, the result would be `/cp-b`, which also
|
||||
// includes `/cp-aa` (etcd uses lexicographic ordering on key ranges for RBAC). Using
|
||||
// `/cp-a/` as the input for the range end calculation results in `/cp-a0`, which doesn't
|
||||
// allow for any other potential control plane key prefixes to be located within the range.
|
||||
// For more information, see also https://etcd.io/docs/v3.3/learning/api/#key-ranges
|
||||
func (e *EtcdClient) buildKey(key string) string {
|
||||
return fmt.Sprintf("/%s/", key)
|
||||
}
|
||||
@@ -181,7 +182,9 @@ func (e *EtcdClient) Migrate(ctx context.Context, tcp kamajiv1alpha1.TenantContr
|
||||
return err
|
||||
}
|
||||
|
||||
response, err := e.Client.Get(ctx, e.buildKey(fmt.Sprintf("%s_%s", tcp.GetNamespace(), tcp.GetName())), etcdclient.WithRange(rangeEnd))
|
||||
key := e.buildKey(fmt.Sprintf("%s_%s", tcp.GetNamespace(), tcp.GetName()))
|
||||
|
||||
response, err := e.Client.Get(ctx, key, etcdclient.WithPrefix())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -30,20 +30,49 @@ func (r *KubernetesIngressResource) ShouldStatusBeUpdated(_ context.Context, tcp
|
||||
case tcp.Spec.ControlPlane.Ingress == nil && tcp.Status.Kubernetes.Ingress == nil:
|
||||
// No update in case of no ingress in spec, neither in status.
|
||||
return false
|
||||
case tcp.Spec.ControlPlane.Ingress != nil && tcp.Status.Kubernetes.Ingress == nil,
|
||||
// Must be updated when TCP is using an Ingress, and status is not tracking it
|
||||
// or
|
||||
// Must be updated when the status is referring to an Ingress, although spec doesn't.
|
||||
tcp.Spec.ControlPlane.Ingress == nil && tcp.Status.Kubernetes.Ingress != nil:
|
||||
case tcp.Spec.ControlPlane.Ingress != nil && tcp.Status.Kubernetes.Ingress == nil, // TCP is using an Ingress, Status not tracking it
|
||||
tcp.Spec.ControlPlane.Ingress == nil && tcp.Status.Kubernetes.Ingress != nil: // Status tracks an Ingress, Spec doesn't
|
||||
return true
|
||||
case len(r.resource.Status.LoadBalancer.Ingress) > 0 && tcp.Status.Kubernetes.Ingress == nil || tcp.Status.Kubernetes.Ingress.LoadBalancer.Ingress == nil:
|
||||
// Must be updated since missing the Ingress status
|
||||
return true
|
||||
case r.resource.Status.LoadBalancer.Ingress[0].IP != tcp.Status.Kubernetes.Ingress.LoadBalancer.Ingress[0].IP:
|
||||
// Must bne updated, Ingress load balancer IP is slightly different
|
||||
case len(tcp.Status.Kubernetes.Ingress.IngressStatus.LoadBalancer.Ingress) != len(r.resource.Status.LoadBalancer.Ingress):
|
||||
// Mismatch count of tracked LoadBalancer Ingress
|
||||
return true
|
||||
default:
|
||||
return tcp.Status.Kubernetes.Ingress.Name != r.resource.GetName() || tcp.Status.Kubernetes.Ingress.Namespace != r.resource.GetNamespace()
|
||||
statusIngress := tcp.Status.Kubernetes.Ingress.IngressStatus.LoadBalancer.Ingress
|
||||
|
||||
for i, ingress := range r.resource.Status.LoadBalancer.Ingress {
|
||||
if ingress.IP != statusIngress[i].IP {
|
||||
return true
|
||||
}
|
||||
|
||||
if len(ingress.Ports) != len(statusIngress[i].Ports) {
|
||||
return true
|
||||
}
|
||||
|
||||
for p, port := range ingress.Ports {
|
||||
if port.Port != statusIngress[i].Ports[p].Port {
|
||||
return true
|
||||
}
|
||||
|
||||
if port.Protocol != statusIngress[i].Ports[p].Protocol {
|
||||
return true
|
||||
}
|
||||
|
||||
if port.Error == nil && statusIngress[i].Ports[p].Error != nil ||
|
||||
port.Error != nil && statusIngress[i].Ports[p].Error == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if port.Error == nil && statusIngress[i].Ports[p].Error == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if *port.Error != *statusIngress[i].Ports[p].Error {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -53,8 +54,7 @@ func (r *KubernetesServiceResource) UpdateTenantControlPlaneStatus(ctx context.C
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
tenantControlPlane.Status.ControlPlaneEndpoint = fmt.Sprintf("%s:%d", address, tenantControlPlane.Spec.NetworkProfile.Port)
|
||||
tenantControlPlane.Status.ControlPlaneEndpoint = net.JoinHostPort(address, strconv.FormatInt(int64(tenantControlPlane.Spec.NetworkProfile.Port), 10))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -74,7 +75,7 @@ func (r *KubeadmConfigResource) getControlPlaneEndpoint(ingress *kamajiv1alpha1.
|
||||
address, port = utilities.GetControlPlaneAddressAndPortFromHostname(ingress.Hostname, port)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s:%d", address, port)
|
||||
return net.JoinHostPort(address, strconv.FormatInt(int64(port), 10))
|
||||
}
|
||||
|
||||
func (r *KubeadmConfigResource) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {
|
||||
|
||||
97
internal/webhook/handlers/tcp_telemetry.go
Normal file
97
internal/webhook/handlers/tcp_telemetry.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/clastix/kamaji-telemetry/api"
|
||||
kamajitelemetry "github.com/clastix/kamaji-telemetry/pkg/client"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/webhook/utils"
|
||||
)
|
||||
|
||||
type TenantControlPlaneTelemetry struct {
|
||||
Enabled bool
|
||||
TelemetryClient kamajitelemetry.Client
|
||||
KamajiVersion string
|
||||
KubernetesVersion string
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneTelemetry) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
if t.Enabled {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
go t.TelemetryClient.PushCreate(context.Background(), api.Create{
|
||||
KamajiVersion: t.KamajiVersion,
|
||||
KubernetesVersion: t.KubernetesVersion,
|
||||
TenantVersion: tcp.Spec.Kubernetes.Version,
|
||||
ClusterAPIOwned: func() bool {
|
||||
for _, owner := range tcp.OwnerReferences {
|
||||
if owner.Kind == "KamajiControlPlane" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}(),
|
||||
NetworkProfile: func() string {
|
||||
switch {
|
||||
case tcp.Spec.ControlPlane.Ingress != nil:
|
||||
return api.NetworkProfileIngress
|
||||
case tcp.Spec.ControlPlane.Service.ServiceType == kamajiv1alpha1.ServiceTypeLoadBalancer:
|
||||
return api.NetworkProfileLB
|
||||
case tcp.Spec.ControlPlane.Service.ServiceType == kamajiv1alpha1.ServiceTypeNodePort:
|
||||
return api.NetworkProfileNodePort
|
||||
case tcp.Spec.ControlPlane.Service.ServiceType == kamajiv1alpha1.ServiceTypeClusterIP:
|
||||
return api.NetworkProfileClusterIP
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}(),
|
||||
})
|
||||
}
|
||||
|
||||
return utils.NilOp()
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneTelemetry) OnDelete(object runtime.Object) AdmissionResponse {
|
||||
if t.Enabled {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
go t.TelemetryClient.PushDelete(context.Background(), api.Delete{
|
||||
KamajiVersion: t.KamajiVersion,
|
||||
KubernetesVersion: t.KubernetesVersion,
|
||||
TenantVersion: tcp.Spec.Kubernetes.Version,
|
||||
Status: t.extractTCPVersion(tcp.Status.Kubernetes.Version.Status),
|
||||
})
|
||||
}
|
||||
|
||||
return utils.NilOp()
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneTelemetry) OnUpdate(newObject runtime.Object, prevObject runtime.Object) AdmissionResponse {
|
||||
if t.Enabled {
|
||||
prevTCP, newTCP := prevObject.(*kamajiv1alpha1.TenantControlPlane), newObject.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
go t.TelemetryClient.PushUpdate(context.Background(), api.Update{
|
||||
KamajiVersion: t.KamajiVersion,
|
||||
KubernetesVersion: t.KubernetesVersion,
|
||||
OldTenantVersion: prevTCP.Status.Kubernetes.Version.Version,
|
||||
NewTenantVersion: newTCP.Spec.Kubernetes.Version,
|
||||
})
|
||||
}
|
||||
|
||||
return utils.NilOp()
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneTelemetry) extractTCPVersion(status *kamajiv1alpha1.KubernetesVersionStatus) string {
|
||||
if status == nil {
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
return string(*status)
|
||||
}
|
||||
22
internal/webhook/routes/tcp_telemetry.go
Normal file
22
internal/webhook/routes/tcp_telemetry.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
//+kubebuilder:webhook:path=/telemetry,mutating=false,failurePolicy=ignore,sideEffects=None,groups=kamaji.clastix.io,resources=tenantcontrolplanes,verbs=create;update;delete,versions=v1alpha1,name=telemetry.kamaji.clastix.io,admissionReviewVersions=v1
|
||||
|
||||
type TenantControlPlaneTelemetry struct{}
|
||||
|
||||
func (t TenantControlPlaneTelemetry) GetPath() string {
|
||||
return "/telemetry"
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneTelemetry) GetObject() runtime.Object {
|
||||
return &kamajiv1alpha1.TenantControlPlane{}
|
||||
}
|
||||
Reference in New Issue
Block a user