mirror of
https://github.com/clastix/kamaji.git
synced 2026-02-24 06:44:03 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4c0cec4f9 | ||
|
|
db3a092d3d | ||
|
|
d590b9d17d | ||
|
|
9147ae9977 | ||
|
|
d2ff044228 | ||
|
|
a147869944 | ||
|
|
056ad4002a | ||
|
|
91cbf0c507 | ||
|
|
d57d5b5a56 | ||
|
|
24714d7168 | ||
|
|
422d225682 | ||
|
|
c57c07693f | ||
|
|
fa560446f1 | ||
|
|
6ba4b4abac | ||
|
|
45d0869b91 | ||
|
|
511a08889e | ||
|
|
6217f2ca25 | ||
|
|
e51df96777 | ||
|
|
f235689bf5 | ||
|
|
aed48e1bf0 | ||
|
|
0037e6e689 | ||
|
|
56071434e6 | ||
|
|
2d39c9ab0b | ||
|
|
b2fbb52361 | ||
|
|
a2236e76cf | ||
|
|
b1ea75f9c0 | ||
|
|
6aea80ce45 | ||
|
|
5ebe123994 | ||
|
|
d1910cd389 | ||
|
|
203e168397 | ||
|
|
b29a79da36 | ||
|
|
5ec586960f | ||
|
|
90aef60c18 | ||
|
|
9ce8da0b37 | ||
|
|
9d73905965 | ||
|
|
32383be1d0 | ||
|
|
6ffd6bbdfd | ||
|
|
b7169215ae | ||
|
|
f8a0206785 | ||
|
|
1d548665ee | ||
|
|
37616865b4 | ||
|
|
d31b3eab0a | ||
|
|
28a098af21 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -32,5 +32,8 @@ bin
|
||||
**/*.key
|
||||
**/*.pem
|
||||
**/*.csr
|
||||
**/server-csr.json
|
||||
.DS_Store
|
||||
|
||||
**/server-csr.json
|
||||
!deploy/kine/mysql/server-csr.json
|
||||
!deploy/kine/nats/server-csr.json
|
||||
|
||||
@@ -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
|
||||
@@ -37,6 +37,8 @@ linters:
|
||||
- funlen
|
||||
- dupl
|
||||
- cyclop
|
||||
- gocognit
|
||||
- nestif
|
||||
# deprecated linters
|
||||
- deadcode
|
||||
- golint
|
||||
|
||||
@@ -7,12 +7,16 @@ 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). |
|
||||
| End-user | sevensphere | 2023 | [link](https://www.sevensphere.io) | Sevensphere provides consulting services for end-user companies / cloud providers and uses Kamaji for designing cloud/on-premises Kubernetes-as-a-Service platform. |
|
||||
| Vendor | Ænix | 2023 | [link](https://aenix.io/) | Ænix provides consulting services for cloud providers and uses Kamaji for running Kubernetes-as-a-Service in free PaaS platform [Cozystack](https://cozystack.io). |
|
||||
| Vendor | Netsons | 2023 | [link](https://www.netsons.com) | Netsons is an Italian hosting and cloud provider and uses Kamaji in its [Managed Kubernetes](https://www.netsons.com/kubernetes) offering. |
|
||||
| Vendor | Aknostic | 2023 | [link](https://aknostic.com) | Aknostic is a cloud-native consultancy company using Kamaji to build a Kubernetes based PaaS. |
|
||||
|
||||
|
||||
### Adopter Types
|
||||
|
||||
**End-user**: The organization runs Kamaji in production in some way.
|
||||
@@ -20,3 +24,5 @@ Feel free to open a Pull-Request to get yours listed.
|
||||
**Integration**: The organization has a product that integrates with Kamaji, but does not contain Kamaji.
|
||||
|
||||
**Vendor**: The organization packages Kamaji in their product and sells it as part of their product.
|
||||
|
||||
**R&D**: Company that exploring innovative technologies and solutions for research and development purposes.
|
||||
|
||||
20
Makefile
20
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.5.0
|
||||
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")
|
||||
@@ -132,7 +132,11 @@ datastore-postgres:
|
||||
$(MAKE) NAME=gold _datastore-postgres
|
||||
|
||||
_datastore-etcd:
|
||||
$(HELM) upgrade --install etcd-$(NAME) clastix/kamaji-etcd --create-namespace -n etcd-system --set datastore.enabled=true
|
||||
$(HELM) upgrade --install etcd-$(NAME) clastix/kamaji-etcd --create-namespace -n etcd-system --set datastore.enabled=true --set fullnameOverride=etcd-$(NAME)
|
||||
|
||||
_datastore-nats:
|
||||
$(MAKE) NAME=$(NAME) NAMESPACE=nats-system -C deploy/kine/nats nats
|
||||
kubectl apply -f $(shell pwd)/config/samples/kamaji_v1alpha1_datastore_nats_$(NAME).yaml
|
||||
|
||||
datastore-etcd: helm
|
||||
$(HELM) repo add clastix https://clastix.github.io/charts
|
||||
@@ -141,7 +145,15 @@ datastore-etcd: helm
|
||||
$(MAKE) NAME=silver _datastore-etcd
|
||||
$(MAKE) NAME=gold _datastore-etcd
|
||||
|
||||
datastores: datastore-mysql datastore-etcd datastore-postgres ## Install all Kamaji DataStores with multiple drivers, and different tiers.
|
||||
datastore-nats: helm
|
||||
$(HELM) repo add nats https://nats-io.github.io/k8s/helm/charts/
|
||||
$(HELM) repo update
|
||||
$(MAKE) NAME=bronze _datastore-nats
|
||||
$(MAKE) NAME=silver _datastore-nats
|
||||
$(MAKE) NAME=gold _datastore-nats
|
||||
$(MAKE) NAME=notls _datastore-nats
|
||||
|
||||
datastores: datastore-mysql datastore-etcd datastore-postgres datastore-nats ## Install all Kamaji DataStores with multiple drivers, and different tiers.
|
||||
|
||||
##@ Build
|
||||
|
||||
@@ -295,7 +307,7 @@ 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) upgrade --debug --install kamaji ./charts/kamaji --create-namespace --namespace kamaji-system --set "image.pullPolicy=Never" --set "telemetry.disabled=true"
|
||||
$(MAKE) datastores
|
||||
$(GINKGO) -v ./e2e
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ The state is managed by the `Datastore` API, a cluster-scoped resource which can
|
||||
- **Managing core addons**: Kamaji allows configuring automatically `kube-proxy`, `CoreDNS`, and `konnectivity`, with automatic remediation in case of user errors (e.g.: deleting the `CoreDNS` deployment).
|
||||
- **Auto Healing**: the `TenantControlPlane` objects in the management cluster are tracked by Kamaji, in case of deletion of those, everything is created in an idempotent way.
|
||||
- **Datastore multi-tenancy**: optionally, Kamaji allows running multiple Control Planes on the same _Datastore_ instance leveraging on the multi-tenancy of each driver, decreasing operations and optimizing costs.
|
||||
- **Overcoming `etcd` limitations**: optionally, Kamaji allows using a different _Datastore_ thanks to [`kine`](https://github.com/k3s-io/kine) by supporting `MySQL` or `PostgreSQL` as an alternative.
|
||||
- **Overcoming `etcd` limitations**: optionally, Kamaji allows using a different _Datastore_ thanks to [`kine`](https://github.com/k3s-io/kine) by supporting `MySQL`, `PostgreSQL`, or `NATS` as an alternative.
|
||||
- **Simplifying mixed-networks setup**: thanks to [`Konnectivity`](https://kubernetes.io/docs/tasks/extend-kubernetes/setup-konnectivity/),
|
||||
the Tenant Control Plane is connected to the worker nodes hosted in a different network, overcoming the no-NAT availability when dealing with nodes with a non routable IP address
|
||||
(e.g.: worker nodes in a different infrastructure).
|
||||
@@ -104,7 +104,7 @@ Since Kamaji is just focusing on the Control Plane a [Kamaji's Cluster API Contr
|
||||
- [x] Dynamic address on Load Balancer
|
||||
- [x] Zero Downtime Tenant Control Plane upgrade
|
||||
- [x] [Join worker nodes from anywhere thanks to Konnectivity](https://kamaji.clastix.io/concepts/#konnectivity)
|
||||
- [x] [Alternative datastore MySQL and PostgreSQL](https://kamaji.clastix.io/guides/alternative-datastore/)
|
||||
- [x] [Alternative datastore MySQL, PostgreSQL, NATS](https://kamaji.clastix.io/guides/alternative-datastore/)
|
||||
- [x] [Pool of multiple datastores](https://kamaji.clastix.io/concepts/#datastores)
|
||||
- [x] [Seamless migration between datastores](https://kamaji.clastix.io/guides/datastore-migration/)
|
||||
- [ ] Automatic assignment to a datastore
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// +kubebuilder:validation:Enum=etcd;MySQL;PostgreSQL
|
||||
// +kubebuilder:validation:Enum=etcd;MySQL;PostgreSQL;NATS
|
||||
|
||||
type Driver string
|
||||
|
||||
@@ -16,6 +16,7 @@ var (
|
||||
EtcdDriver Driver = "etcd"
|
||||
KineMySQLDriver Driver = "MySQL"
|
||||
KinePostgreSQLDriver Driver = "PostgreSQL"
|
||||
KineNatsDriver Driver = "NATS"
|
||||
)
|
||||
|
||||
// +kubebuilder:validation:MinItems=1
|
||||
@@ -33,7 +34,8 @@ type DataStoreSpec struct {
|
||||
// This value is optional.
|
||||
BasicAuth *BasicAuth `json:"basicAuth,omitempty"`
|
||||
// Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
TLSConfig TLSConfig `json:"tlsConfig"`
|
||||
// This value is optional.
|
||||
TLSConfig *TLSConfig `json:"tlsConfig,omitempty"`
|
||||
}
|
||||
|
||||
// TLSConfig contains the information used to connect to the data store using a secured connection.
|
||||
@@ -42,7 +44,7 @@ type TLSConfig struct {
|
||||
// The key reference is required since etcd authentication is based on certificates, and Kamaji is responsible in creating this.
|
||||
CertificateAuthority CertKeyPair `json:"certificateAuthority"`
|
||||
// Specifies the SSL/TLS key and private key pair used to connect to the data store.
|
||||
ClientCertificate ClientCertificate `json:"clientCertificate"`
|
||||
ClientCertificate *ClientCertificate `json:"clientCertificate,omitempty"`
|
||||
}
|
||||
|
||||
type ClientCertificate struct {
|
||||
|
||||
@@ -43,20 +43,22 @@ func (d *DatastoreUsedSecret) ExtractValue() client.IndexerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
if ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef))
|
||||
}
|
||||
if ds.Spec.TLSConfig != nil {
|
||||
if ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.Certificate.SecretRef))
|
||||
}
|
||||
|
||||
if ds.Spec.TLSConfig.CertificateAuthority.PrivateKey != nil && ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef))
|
||||
}
|
||||
if ds.Spec.TLSConfig.CertificateAuthority.PrivateKey != nil && ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.CertificateAuthority.PrivateKey.SecretRef))
|
||||
}
|
||||
|
||||
if ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef))
|
||||
}
|
||||
if ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.Certificate.SecretRef))
|
||||
}
|
||||
|
||||
if ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef))
|
||||
if ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef != nil {
|
||||
res = append(res, d.namespacedName(*ds.Spec.TLSConfig.ClientCertificate.PrivateKey.SecretRef))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
@@ -141,8 +141,9 @@ type DeploymentSpec struct {
|
||||
// such as kube-apiserver, controller-manager, and scheduler. WARNING - This option
|
||||
// can override existing parameters and cause components to misbehave in unxpected ways.
|
||||
// Only modify if you know what you are doing.
|
||||
ExtraArgs *ControlPlaneExtraArgs `json:"extraArgs,omitempty"`
|
||||
AdditionalMetadata AdditionalMetadata `json:"additionalMetadata,omitempty"`
|
||||
ExtraArgs *ControlPlaneExtraArgs `json:"extraArgs,omitempty"`
|
||||
AdditionalMetadata AdditionalMetadata `json:"additionalMetadata,omitempty"`
|
||||
PodAdditionalMetadata AdditionalMetadata `json:"podAdditionalMetadata,omitempty"`
|
||||
// AdditionalInitContainers allows adding additional init containers to the Control Plane deployment.
|
||||
AdditionalInitContainers []corev1.Container `json:"additionalInitContainers,omitempty"`
|
||||
// AdditionalContainers allows adding additional containers to the Control Plane deployment.
|
||||
@@ -152,6 +153,9 @@ type DeploymentSpec struct {
|
||||
// AdditionalVolumeMounts allows to mount an additional volume into each component of the Control Plane
|
||||
// (kube-apiserver, controller-manager, and scheduler).
|
||||
AdditionalVolumeMounts *AdditionalVolumeMounts `json:"additionalVolumeMounts,omitempty"`
|
||||
// +kubebuilder:default="default"
|
||||
// ServiceAccountName allows to specify the service account to be mounted to the pods of the Control plane deployment
|
||||
ServiceAccountName string `json:"serviceAccountName,omitempty"`
|
||||
}
|
||||
|
||||
// AdditionalVolumeMounts allows mounting additional volumes to the Control Plane components.
|
||||
@@ -216,8 +220,12 @@ type KonnectivityAgentSpec struct {
|
||||
Image string `json:"image,omitempty"`
|
||||
// Version for Konnectivity agent.
|
||||
// +kubebuilder:default=v0.0.32
|
||||
Version string `json:"version,omitempty"`
|
||||
ExtraArgs ExtraArgs `json:"extraArgs,omitempty"`
|
||||
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.
|
||||
// +kubebuilder:default={{key: "CriticalAddonsOnly", operator: "Exists"}}
|
||||
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
||||
ExtraArgs ExtraArgs `json:"extraArgs,omitempty"`
|
||||
}
|
||||
|
||||
// KonnectivitySpec defines the spec for Konnectivity.
|
||||
@@ -258,7 +266,7 @@ type TenantControlPlaneSpec struct {
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:subresource:scale:specpath=.spec.controlPlane.deployment.replicas,statuspath=.status.kubernetesResources.deployment.replicas,selectorpath=.status.kubernetesResources.deployment.selector
|
||||
// +kubebuilder:resource:shortName=tcp
|
||||
// +kubebuilder:resource:categories=kamaji,shortName=tcp
|
||||
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.kubernetes.version",description="Kubernetes version"
|
||||
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.kubernetesResources.version.status",description="Status"
|
||||
// +kubebuilder:printcolumn:name="Control-Plane endpoint",type="string",JSONPath=".status.controlPlaneEndpoint",description="Tenant Control Plane Endpoint (API server)"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
@@ -526,7 +525,11 @@ func (in *DataStoreSpec) DeepCopyInto(out *DataStoreSpec) {
|
||||
*out = new(BasicAuth)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.TLSConfig.DeepCopyInto(&out.TLSConfig)
|
||||
if in.TLSConfig != nil {
|
||||
in, out := &in.TLSConfig, &out.TLSConfig
|
||||
*out = new(TLSConfig)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataStoreSpec.
|
||||
@@ -578,6 +581,11 @@ func (in *DatastoreUsedSecret) DeepCopy() *DatastoreUsedSecret {
|
||||
func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) {
|
||||
*out = *in
|
||||
out.RegistrySettings = in.RegistrySettings
|
||||
if in.Replicas != nil {
|
||||
in, out := &in.Replicas, &out.Replicas
|
||||
*out = new(int32)
|
||||
**out = **in
|
||||
}
|
||||
if in.NodeSelector != nil {
|
||||
in, out := &in.NodeSelector, &out.NodeSelector
|
||||
*out = make(map[string]string, len(*in))
|
||||
@@ -616,6 +624,7 @@ func (in *DeploymentSpec) DeepCopyInto(out *DeploymentSpec) {
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
in.AdditionalMetadata.DeepCopyInto(&out.AdditionalMetadata)
|
||||
in.PodAdditionalMetadata.DeepCopyInto(&out.PodAdditionalMetadata)
|
||||
if in.AdditionalInitContainers != nil {
|
||||
in, out := &in.AdditionalInitContainers, &out.AdditionalInitContainers
|
||||
*out = make([]v1.Container, len(*in))
|
||||
@@ -775,6 +784,13 @@ func (in *IngressSpec) DeepCopy() *IngressSpec {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *KonnectivityAgentSpec) DeepCopyInto(out *KonnectivityAgentSpec) {
|
||||
*out = *in
|
||||
if in.Tolerations != nil {
|
||||
in, out := &in.Tolerations, &out.Tolerations
|
||||
*out = make([]v1.Toleration, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.ExtraArgs != nil {
|
||||
in, out := &in.ExtraArgs, &out.ExtraArgs
|
||||
*out = make(ExtraArgs, len(*in))
|
||||
@@ -1196,7 +1212,11 @@ func (in *StorageStatus) DeepCopy() *StorageStatus {
|
||||
func (in *TLSConfig) DeepCopyInto(out *TLSConfig) {
|
||||
*out = *in
|
||||
in.CertificateAuthority.DeepCopyInto(&out.CertificateAuthority)
|
||||
in.ClientCertificate.DeepCopyInto(&out.ClientCertificate)
|
||||
if in.ClientCertificate != nil {
|
||||
in, out := &in.ClientCertificate, &out.ClientCertificate
|
||||
*out = new(ClientCertificate)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
appVersion: v0.5.0
|
||||
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,7 +17,7 @@ name: kamaji
|
||||
sources:
|
||||
- https://github.com/clastix/kamaji
|
||||
type: application
|
||||
version: 0.15.2
|
||||
version: 1.0.0
|
||||
annotations:
|
||||
catalog.cattle.io/certified: partner
|
||||
catalog.cattle.io/release-name: kamaji
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# kamaji
|
||||
|
||||
  
|
||||
  
|
||||
|
||||
Kamaji is the Hosted Control Plane Manager for Kubernetes.
|
||||
|
||||
@@ -77,7 +77,7 @@ Here the values you can override:
|
||||
| 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.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. |
|
||||
@@ -90,6 +90,7 @@ Here the values you can override:
|
||||
| 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 |
|
||||
@@ -133,6 +134,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 |
|
||||
|
||||
|
||||
@@ -71,10 +71,12 @@ spec:
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is unique within a namespace to reference a secret resource.
|
||||
description: name is unique within a namespace to reference
|
||||
a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: namespace defines the space within which the secret name must be unique.
|
||||
description: namespace defines the space within which
|
||||
the secret name must be unique.
|
||||
type: string
|
||||
required:
|
||||
- keyPath
|
||||
@@ -98,10 +100,12 @@ spec:
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is unique within a namespace to reference a secret resource.
|
||||
description: name is unique within a namespace to reference
|
||||
a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: namespace defines the space within which the secret name must be unique.
|
||||
description: namespace defines the space within which
|
||||
the secret name must be unique.
|
||||
type: string
|
||||
required:
|
||||
- keyPath
|
||||
@@ -118,6 +122,7 @@ spec:
|
||||
- etcd
|
||||
- MySQL
|
||||
- PostgreSQL
|
||||
- NATS
|
||||
type: string
|
||||
endpoints:
|
||||
description: |-
|
||||
@@ -128,7 +133,9 @@ spec:
|
||||
minItems: 1
|
||||
type: array
|
||||
tlsConfig:
|
||||
description: Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
description: |-
|
||||
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
This value is optional.
|
||||
properties:
|
||||
certificateAuthority:
|
||||
description: |-
|
||||
@@ -152,10 +159,12 @@ spec:
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is unique within a namespace to reference a secret resource.
|
||||
description: name is unique within a namespace to
|
||||
reference a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: namespace defines the space within which the secret name must be unique.
|
||||
description: namespace defines the space within which
|
||||
the secret name must be unique.
|
||||
type: string
|
||||
required:
|
||||
- keyPath
|
||||
@@ -179,10 +188,12 @@ spec:
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is unique within a namespace to reference a secret resource.
|
||||
description: name is unique within a namespace to
|
||||
reference a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: namespace defines the space within which the secret name must be unique.
|
||||
description: namespace defines the space within which
|
||||
the secret name must be unique.
|
||||
type: string
|
||||
required:
|
||||
- keyPath
|
||||
@@ -193,7 +204,8 @@ spec:
|
||||
- certificate
|
||||
type: object
|
||||
clientCertificate:
|
||||
description: Specifies the SSL/TLS key and private key pair used to connect to the data store.
|
||||
description: Specifies the SSL/TLS key and private key pair used
|
||||
to connect to the data store.
|
||||
properties:
|
||||
certificate:
|
||||
properties:
|
||||
@@ -212,10 +224,12 @@ spec:
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is unique within a namespace to reference a secret resource.
|
||||
description: name is unique within a namespace to
|
||||
reference a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: namespace defines the space within which the secret name must be unique.
|
||||
description: namespace defines the space within which
|
||||
the secret name must be unique.
|
||||
type: string
|
||||
required:
|
||||
- keyPath
|
||||
@@ -239,10 +253,12 @@ spec:
|
||||
minLength: 1
|
||||
type: string
|
||||
name:
|
||||
description: name is unique within a namespace to reference a secret resource.
|
||||
description: name is unique within a namespace to
|
||||
reference a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: namespace defines the space within which the secret name must be unique.
|
||||
description: namespace defines the space within which
|
||||
the secret name must be unique.
|
||||
type: string
|
||||
required:
|
||||
- keyPath
|
||||
@@ -255,18 +271,17 @@ spec:
|
||||
type: object
|
||||
required:
|
||||
- certificateAuthority
|
||||
- clientCertificate
|
||||
type: object
|
||||
required:
|
||||
- driver
|
||||
- endpoints
|
||||
- tlsConfig
|
||||
type: object
|
||||
status:
|
||||
description: DataStoreStatus defines the observed state of DataStore.
|
||||
properties:
|
||||
usedBy:
|
||||
description: List of the Tenant Control Planes, namespaced named, using this data store.
|
||||
description: List of the Tenant Control Planes, namespaced named,
|
||||
using this data store.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,9 @@ spec:
|
||||
- --metrics-bind-address={{ .Values.metricsBindAddress }}
|
||||
- --tmp-directory={{ .Values.temporaryDirectoryPath }}
|
||||
- --datastore={{ include "datastore.fullname" . }}
|
||||
{{- if .Values.telemetry.disabled }}
|
||||
- --disable-telemetry
|
||||
{{- end }}
|
||||
{{- if .Values.loggingDevel.enable }}
|
||||
- --zap-devel
|
||||
{{- end }}
|
||||
|
||||
@@ -20,9 +20,14 @@ spec:
|
||||
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}}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -60,7 +60,7 @@ etcd:
|
||||
# -- The custom annotations to add to the PVC
|
||||
customAnnotations: {}
|
||||
# volumeType: local
|
||||
|
||||
|
||||
# -- (array) Kubernetes affinity rules to apply to Kamaji etcd pods
|
||||
tolerations: []
|
||||
|
||||
@@ -162,7 +162,7 @@ loggingDevel:
|
||||
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.
|
||||
# -- (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
|
||||
@@ -184,6 +184,7 @@ datastore:
|
||||
# -- 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.
|
||||
@@ -218,4 +219,9 @@ datastore:
|
||||
cfssl:
|
||||
image:
|
||||
repository: cfssl/cfssl
|
||||
tag: latest
|
||||
tag: latest
|
||||
|
||||
# -- 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")
|
||||
|
||||
@@ -175,7 +209,9 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
handlers.Freeze{},
|
||||
},
|
||||
routes.TenantControlPlaneDefaults{}: {
|
||||
handlers.TenantControlPlaneDefaults{DefaultDatastore: datastore},
|
||||
handlers.TenantControlPlaneDefaults{
|
||||
DefaultDatastore: datastore,
|
||||
},
|
||||
},
|
||||
routes.TenantControlPlaneValidate{}: {
|
||||
handlers.TenantControlPlaneName{},
|
||||
@@ -192,6 +228,15 @@ func NewCmd(scheme *runtime.Scheme) *cobra.Command {
|
||||
Scheme: *mgr.GetScheme(),
|
||||
},
|
||||
},
|
||||
handlers.TenantControlPlaneServiceCIDR{},
|
||||
},
|
||||
routes.TenantControlPlaneTelemetry{}: {
|
||||
handlers.TenantControlPlaneTelemetry{
|
||||
Enabled: !disableTelemetry,
|
||||
TelemetryClient: telemetryClient,
|
||||
KamajiVersion: internal.GitTag,
|
||||
KubernetesVersion: k8sVersion,
|
||||
},
|
||||
},
|
||||
routes.DataStoreValidate{}: {
|
||||
handlers.DataStoreValidation{Client: mgr.GetClient()},
|
||||
@@ -262,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
|
||||
}
|
||||
@@ -121,6 +121,7 @@ spec:
|
||||
- etcd
|
||||
- MySQL
|
||||
- PostgreSQL
|
||||
- NATS
|
||||
type: string
|
||||
endpoints:
|
||||
description: |-
|
||||
@@ -131,8 +132,9 @@ spec:
|
||||
minItems: 1
|
||||
type: array
|
||||
tlsConfig:
|
||||
description: Defines the TLS/SSL configuration required to connect
|
||||
to the data store in a secure way.
|
||||
description: |-
|
||||
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
This value is optional.
|
||||
properties:
|
||||
certificateAuthority:
|
||||
description: |-
|
||||
@@ -268,12 +270,10 @@ spec:
|
||||
type: object
|
||||
required:
|
||||
- certificateAuthority
|
||||
- clientCertificate
|
||||
type: object
|
||||
required:
|
||||
- driver
|
||||
- endpoints
|
||||
- tlsConfig
|
||||
type: object
|
||||
status:
|
||||
description: DataStoreStatus defines the observed state of DataStore.
|
||||
|
||||
@@ -8,6 +8,8 @@ metadata:
|
||||
spec:
|
||||
group: kamaji.clastix.io
|
||||
names:
|
||||
categories:
|
||||
- kamaji
|
||||
kind: TenantControlPlane
|
||||
listKind: TenantControlPlaneList
|
||||
plural: tenantcontrolplanes
|
||||
@@ -109,6 +111,50 @@ spec:
|
||||
description: AgentImage defines the container image for
|
||||
Konnectivity's agent.
|
||||
type: string
|
||||
tolerations:
|
||||
default:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Exists
|
||||
description: |-
|
||||
Tolerations for the deployed agent.
|
||||
Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.
|
||||
items:
|
||||
description: |-
|
||||
The pod this Toleration is attached to tolerates any taint that matches
|
||||
the triple <key,value,effect> using the matching operator <operator>.
|
||||
properties:
|
||||
effect:
|
||||
description: |-
|
||||
Effect indicates the taint effect to match. Empty means match all taint effects.
|
||||
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
|
||||
type: string
|
||||
key:
|
||||
description: |-
|
||||
Key is the taint key that the toleration applies to. Empty means match all taint keys.
|
||||
If the key is empty, operator must be Exists; this combination means to match all values and all keys.
|
||||
type: string
|
||||
operator:
|
||||
description: |-
|
||||
Operator represents a key's relationship to the value.
|
||||
Valid operators are Exists and Equal. Defaults to Equal.
|
||||
Exists is equivalent to wildcard for value, so that a pod can
|
||||
tolerate all taints of a particular category.
|
||||
type: string
|
||||
tolerationSeconds:
|
||||
description: |-
|
||||
TolerationSeconds represents the period of time the toleration (which must be
|
||||
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
|
||||
it is not set, which means tolerate the taint forever (do not evict). Zero and
|
||||
negative values will be treated as 0 (evict immediately) by the system.
|
||||
format: int64
|
||||
type: integer
|
||||
value:
|
||||
description: |-
|
||||
Value is the taint value the toleration matches to.
|
||||
If the operator is Exists, the value should be empty, otherwise just a regular string.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
version:
|
||||
default: v0.0.32
|
||||
description: Version for Konnectivity agent.
|
||||
@@ -301,10 +347,15 @@ spec:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap
|
||||
@@ -367,10 +418,15 @@ spec:
|
||||
key.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret
|
||||
@@ -404,10 +460,15 @@ spec:
|
||||
description: The ConfigMap to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap
|
||||
@@ -423,10 +484,15 @@ spec:
|
||||
description: The Secret to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret must
|
||||
@@ -1727,10 +1793,15 @@ spec:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap
|
||||
@@ -1793,10 +1864,15 @@ spec:
|
||||
key.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret
|
||||
@@ -1830,10 +1906,15 @@ spec:
|
||||
description: The ConfigMap to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap
|
||||
@@ -1849,10 +1930,15 @@ spec:
|
||||
description: The Secret to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret must
|
||||
@@ -3438,10 +3524,15 @@ spec:
|
||||
More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -3477,10 +3568,15 @@ spec:
|
||||
to OpenStack.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -3547,10 +3643,15 @@ spec:
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: optional specify whether the ConfigMap
|
||||
@@ -3583,10 +3684,15 @@ spec:
|
||||
secret object contains more than one secret, all secret references are passed.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4068,10 +4174,15 @@ spec:
|
||||
scripts.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4263,10 +4374,15 @@ spec:
|
||||
target and initiator authentication
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4531,10 +4647,15 @@ spec:
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: optional specify whether
|
||||
@@ -4670,10 +4791,15 @@ spec:
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: optional field specify whether
|
||||
@@ -4804,10 +4930,15 @@ spec:
|
||||
More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4851,10 +4982,15 @@ spec:
|
||||
sensitive information. If this is not provided, Login operation will fail.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4971,10 +5107,15 @@ spec:
|
||||
credentials. If not specified, default values will be attempted.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -5991,6 +6132,20 @@ spec:
|
||||
Selector which must match a node's labels for the pod to be scheduled on that node.
|
||||
More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
|
||||
type: object
|
||||
podAdditionalMetadata:
|
||||
description: AdditionalMetadata defines which additional metadata,
|
||||
such as labels and annotations, must be attached to the
|
||||
created resource.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
registrySettings:
|
||||
default:
|
||||
apiServerImage: kube-apiserver
|
||||
@@ -6266,6 +6421,11 @@ spec:
|
||||
empty definition that uses the default runtime handler.
|
||||
More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class
|
||||
type: string
|
||||
serviceAccountName:
|
||||
default: default
|
||||
description: ServiceAccountName allows to specify the service
|
||||
account to be mounted to the pods of the Control plane deployment
|
||||
type: string
|
||||
strategy:
|
||||
default:
|
||||
rollingUpdate:
|
||||
|
||||
@@ -127,6 +127,7 @@ spec:
|
||||
- etcd
|
||||
- MySQL
|
||||
- PostgreSQL
|
||||
- NATS
|
||||
type: string
|
||||
endpoints:
|
||||
description: |-
|
||||
@@ -137,7 +138,9 @@ spec:
|
||||
minItems: 1
|
||||
type: array
|
||||
tlsConfig:
|
||||
description: Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
description: |-
|
||||
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
This value is optional.
|
||||
properties:
|
||||
certificateAuthority:
|
||||
description: |-
|
||||
@@ -264,12 +267,10 @@ spec:
|
||||
type: object
|
||||
required:
|
||||
- certificateAuthority
|
||||
- clientCertificate
|
||||
type: object
|
||||
required:
|
||||
- driver
|
||||
- endpoints
|
||||
- tlsConfig
|
||||
type: object
|
||||
status:
|
||||
description: DataStoreStatus defines the observed state of DataStore.
|
||||
@@ -308,6 +309,8 @@ spec:
|
||||
- v1
|
||||
group: kamaji.clastix.io
|
||||
names:
|
||||
categories:
|
||||
- kamaji
|
||||
kind: TenantControlPlane
|
||||
listKind: TenantControlPlaneList
|
||||
plural: tenantcontrolplanes
|
||||
@@ -406,6 +409,50 @@ spec:
|
||||
default: registry.k8s.io/kas-network-proxy/proxy-agent
|
||||
description: AgentImage defines the container image for Konnectivity's agent.
|
||||
type: string
|
||||
tolerations:
|
||||
default:
|
||||
- key: CriticalAddonsOnly
|
||||
operator: Exists
|
||||
description: |-
|
||||
Tolerations for the deployed agent.
|
||||
Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.
|
||||
items:
|
||||
description: |-
|
||||
The pod this Toleration is attached to tolerates any taint that matches
|
||||
the triple <key,value,effect> using the matching operator <operator>.
|
||||
properties:
|
||||
effect:
|
||||
description: |-
|
||||
Effect indicates the taint effect to match. Empty means match all taint effects.
|
||||
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
|
||||
type: string
|
||||
key:
|
||||
description: |-
|
||||
Key is the taint key that the toleration applies to. Empty means match all taint keys.
|
||||
If the key is empty, operator must be Exists; this combination means to match all values and all keys.
|
||||
type: string
|
||||
operator:
|
||||
description: |-
|
||||
Operator represents a key's relationship to the value.
|
||||
Valid operators are Exists and Equal. Defaults to Equal.
|
||||
Exists is equivalent to wildcard for value, so that a pod can
|
||||
tolerate all taints of a particular category.
|
||||
type: string
|
||||
tolerationSeconds:
|
||||
description: |-
|
||||
TolerationSeconds represents the period of time the toleration (which must be
|
||||
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
|
||||
it is not set, which means tolerate the taint forever (do not evict). Zero and
|
||||
negative values will be treated as 0 (evict immediately) by the system.
|
||||
format: int64
|
||||
type: integer
|
||||
value:
|
||||
description: |-
|
||||
Value is the taint value the toleration matches to.
|
||||
If the operator is Exists, the value should be empty, otherwise just a regular string.
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
version:
|
||||
default: v0.0.32
|
||||
description: Version for Konnectivity agent.
|
||||
@@ -587,10 +634,15 @@ spec:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its key must be defined
|
||||
@@ -643,10 +695,15 @@ spec:
|
||||
description: The key of the secret to select from. Must be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be defined
|
||||
@@ -678,10 +735,15 @@ spec:
|
||||
description: The ConfigMap to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap must be defined
|
||||
@@ -695,10 +757,15 @@ spec:
|
||||
description: The Secret to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret must be defined
|
||||
@@ -1941,10 +2008,15 @@ spec:
|
||||
description: The key to select.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap or its key must be defined
|
||||
@@ -1997,10 +2069,15 @@ spec:
|
||||
description: The key of the secret to select from. Must be a valid secret key.
|
||||
type: string
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be defined
|
||||
@@ -2032,10 +2109,15 @@ spec:
|
||||
description: The ConfigMap to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the ConfigMap must be defined
|
||||
@@ -2049,10 +2131,15 @@ spec:
|
||||
description: The Secret to select from
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret must be defined
|
||||
@@ -3565,10 +3652,15 @@ spec:
|
||||
More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -3604,10 +3696,15 @@ spec:
|
||||
to OpenStack.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -3672,10 +3769,15 @@ spec:
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: optional specify whether the ConfigMap or its keys must be defined
|
||||
@@ -3705,10 +3807,15 @@ spec:
|
||||
secret object contains more than one secret, all secret references are passed.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4159,10 +4266,15 @@ spec:
|
||||
scripts.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4347,10 +4459,15 @@ spec:
|
||||
description: secretRef is the CHAP Secret for iSCSI target and initiator authentication
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4601,10 +4718,15 @@ spec:
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: optional specify whether the ConfigMap or its keys must be defined
|
||||
@@ -4715,10 +4837,15 @@ spec:
|
||||
type: array
|
||||
x-kubernetes-list-type: atomic
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
optional:
|
||||
description: optional field specify whether the Secret or its key must be defined
|
||||
@@ -4845,10 +4972,15 @@ spec:
|
||||
More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -4889,10 +5021,15 @@ spec:
|
||||
sensitive information. If this is not provided, Login operation will fail.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -5003,10 +5140,15 @@ spec:
|
||||
credentials. If not specified, default values will be attempted.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
@@ -5966,6 +6108,18 @@ spec:
|
||||
Selector which must match a node's labels for the pod to be scheduled on that node.
|
||||
More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
|
||||
type: object
|
||||
podAdditionalMetadata:
|
||||
description: AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.
|
||||
properties:
|
||||
annotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
labels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
registrySettings:
|
||||
default:
|
||||
apiServerImage: kube-apiserver
|
||||
@@ -6234,6 +6388,10 @@ spec:
|
||||
empty definition that uses the default runtime handler.
|
||||
More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class
|
||||
type: string
|
||||
serviceAccountName:
|
||||
default: default
|
||||
description: ServiceAccountName allows to specify the service account to be mounted to the pods of the Control plane deployment
|
||||
type: string
|
||||
strategy:
|
||||
default:
|
||||
rollingUpdate:
|
||||
@@ -7858,7 +8016,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.serviceAccountName
|
||||
image: clastix/kamaji:v0.5.0
|
||||
image: clastix/kamaji:v1.0.0
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -8050,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.5.0
|
||||
newTag: v1.0.0
|
||||
|
||||
34
config/samples/kamaji_v1alpha1_datastore_nats_bronze.yaml
Normal file
34
config/samples/kamaji_v1alpha1_datastore_nats_bronze.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: DataStore
|
||||
metadata:
|
||||
name: nats-bronze
|
||||
spec:
|
||||
driver: NATS
|
||||
endpoints:
|
||||
- bronze-nats.nats-system.svc:4222
|
||||
basicAuth:
|
||||
username:
|
||||
content: YWRtaW4=
|
||||
password:
|
||||
secretReference:
|
||||
name: nats-bronze-config
|
||||
namespace: nats-system
|
||||
keyPath: password
|
||||
tlsConfig:
|
||||
certificateAuthority:
|
||||
certificate:
|
||||
secretReference:
|
||||
name: nats-bronze-config
|
||||
namespace: nats-system
|
||||
keyPath: ca.crt
|
||||
clientCertificate:
|
||||
certificate:
|
||||
secretReference:
|
||||
name: nats-bronze-config
|
||||
namespace: nats-system
|
||||
keyPath: server.crt
|
||||
privateKey:
|
||||
secretReference:
|
||||
name: nats-bronze-config
|
||||
namespace: nats-system
|
||||
keyPath: server.key
|
||||
34
config/samples/kamaji_v1alpha1_datastore_nats_gold.yaml
Normal file
34
config/samples/kamaji_v1alpha1_datastore_nats_gold.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: DataStore
|
||||
metadata:
|
||||
name: nats-gold
|
||||
spec:
|
||||
driver: NATS
|
||||
endpoints:
|
||||
- nats-gold.nats-system.svc:4222
|
||||
basicAuth:
|
||||
username:
|
||||
content: YWRtaW4=
|
||||
password:
|
||||
secretReference:
|
||||
name: nats-gold-config
|
||||
namespace: nats-system
|
||||
keyPath: password
|
||||
tlsConfig:
|
||||
certificateAuthority:
|
||||
certificate:
|
||||
secretReference:
|
||||
name: nats-gold-config
|
||||
namespace: nats-system
|
||||
keyPath: ca.crt
|
||||
clientCertificate:
|
||||
certificate:
|
||||
secretReference:
|
||||
name: nats-gold-config
|
||||
namespace: nats-system
|
||||
keyPath: server.crt
|
||||
privateKey:
|
||||
secretReference:
|
||||
name: nats-gold-config
|
||||
namespace: nats-system
|
||||
keyPath: server.key
|
||||
17
config/samples/kamaji_v1alpha1_datastore_nats_notls.yaml
Normal file
17
config/samples/kamaji_v1alpha1_datastore_nats_notls.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: DataStore
|
||||
metadata:
|
||||
name: nats-notls
|
||||
spec:
|
||||
driver: NATS
|
||||
endpoints:
|
||||
- notls-nats.nats-system.svc:4222
|
||||
basicAuth:
|
||||
username:
|
||||
content: YWRtaW4=
|
||||
password:
|
||||
secretReference:
|
||||
name: nats-notls-config
|
||||
namespace: nats-system
|
||||
keyPath: password
|
||||
|
||||
34
config/samples/kamaji_v1alpha1_datastore_nats_silver.yaml
Normal file
34
config/samples/kamaji_v1alpha1_datastore_nats_silver.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: DataStore
|
||||
metadata:
|
||||
name: nats-silver
|
||||
spec:
|
||||
driver: NATS
|
||||
endpoints:
|
||||
- nats-silver.nats-system.svc:4222
|
||||
basicAuth:
|
||||
username:
|
||||
content: YWRtaW4=
|
||||
password:
|
||||
secretReference:
|
||||
name: nats-silver-config
|
||||
namespace: nats-system
|
||||
keyPath: password
|
||||
tlsConfig:
|
||||
certificateAuthority:
|
||||
certificate:
|
||||
secretReference:
|
||||
name: nats-silver-config
|
||||
namespace: nats-system
|
||||
keyPath: ca.crt
|
||||
clientCertificate:
|
||||
certificate:
|
||||
secretReference:
|
||||
name: nats-silver-config
|
||||
namespace: nats-system
|
||||
keyPath: server.crt
|
||||
privateKey:
|
||||
secretReference:
|
||||
name: nats-silver-config
|
||||
namespace: nats-system
|
||||
keyPath: server.key
|
||||
@@ -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)
|
||||
},
|
||||
|
||||
@@ -205,6 +205,9 @@ func getKubeconfigResources(c client.Client, tcpReconcilerConfig TenantControlPl
|
||||
|
||||
func getKubernetesStorageResources(c client.Client, dbConnection datastore.Connection, datastore kamajiv1alpha1.DataStore) []resources.Resource {
|
||||
return []resources.Resource{
|
||||
&ds.MultiTenancy{
|
||||
DataStore: datastore,
|
||||
},
|
||||
&ds.Config{
|
||||
Client: c,
|
||||
ConnString: dbConnection.GetConnectionString(),
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -26,7 +26,7 @@ nodes:
|
||||
## expose port 31132 of the node to port 31132 on the host for konnectivity
|
||||
- containerPort: 31132
|
||||
hostPort: 31132
|
||||
protocol: TCP
|
||||
protocol: TCP
|
||||
## expose port 31443 of the node to port 31443 on the host
|
||||
- containerPort: 31443
|
||||
hostPort: 31443
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"CN": "bronze.mysql-system.svc.cluster.local",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [
|
||||
"127.0.0.1",
|
||||
"localhost",
|
||||
"bronze",
|
||||
"bronze.mysql-system.svc",
|
||||
"bronze.mysql-system.svc.cluster.local"
|
||||
]
|
||||
}
|
||||
40
deploy/kine/nats/Makefile
Normal file
40
deploy/kine/nats/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
NAME:=default
|
||||
NAMESPACE:=nats-system
|
||||
|
||||
.PHONY: helm
|
||||
HELM = $(shell pwd)/../../../bin/helm
|
||||
helm: ## Download helm locally if necessary.
|
||||
$(call go-install-tool,$(HELM),helm.sh/helm/v3/cmd/helm@v3.9.0)
|
||||
|
||||
nats: nats-certificates nats-secret nats-deployment
|
||||
|
||||
nats-certificates:
|
||||
rm -rf $(ROOT_DIR)/certs/$(NAME) && mkdir -p $(ROOT_DIR)/certs/$(NAME)
|
||||
cfssl gencert -initca $(ROOT_DIR)/ca-csr.json | cfssljson -bare $(ROOT_DIR)/certs/$(NAME)/ca
|
||||
@mv $(ROOT_DIR)/certs/$(NAME)/ca.pem $(ROOT_DIR)/certs/$(NAME)/ca.crt
|
||||
@mv $(ROOT_DIR)/certs/$(NAME)/ca-key.pem $(ROOT_DIR)/certs/$(NAME)/ca.key
|
||||
@NAME=$(NAME) NAMESPACE=$(NAMESPACE) envsubst < server-csr.json > $(ROOT_DIR)/certs/$(NAME)/server-csr.json
|
||||
cfssl gencert -ca=$(ROOT_DIR)/certs/$(NAME)/ca.crt -ca-key=$(ROOT_DIR)/certs/$(NAME)/ca.key \
|
||||
-config=$(ROOT_DIR)/config.json -profile=server \
|
||||
$(ROOT_DIR)/certs/$(NAME)/server-csr.json | cfssljson -bare $(ROOT_DIR)/certs/$(NAME)/server
|
||||
@mv $(ROOT_DIR)/certs/$(NAME)/server.pem $(ROOT_DIR)/certs/$(NAME)/server.crt
|
||||
@mv $(ROOT_DIR)/certs/$(NAME)/server-key.pem $(ROOT_DIR)/certs/$(NAME)/server.key
|
||||
chmod 644 $(ROOT_DIR)/certs/$(NAME)/*
|
||||
|
||||
nats-secret:
|
||||
@kubectl create namespace $(NAMESPACE) || true
|
||||
@kubectl -n $(NAMESPACE) create secret generic nats-$(NAME)-config \
|
||||
--from-file=$(ROOT_DIR)/certs/$(NAME)/ca.crt --from-file=$(ROOT_DIR)/certs/$(NAME)/ca.key \
|
||||
--from-file=$(ROOT_DIR)/certs/$(NAME)/server.key --from-file=$(ROOT_DIR)/certs/$(NAME)/server.crt \
|
||||
--from-literal=password=password \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
nats-deployment:
|
||||
@VALUES_FILE=$(if $(findstring notls,$(NAME)),values-notls.yaml,values.yaml); \
|
||||
NAME=$(NAME) envsubst < $(ROOT_DIR)/$$VALUES_FILE | $(HELM) upgrade --install $(NAME) nats/nats --create-namespace -n nats-system -f -
|
||||
|
||||
|
||||
nats-destroy:
|
||||
@NAME=$(NAME) envsubst < $(ROOT_DIR)/nats.yaml | kubectl -n $(NAMESPACE) delete --ignore-not-found -f -
|
||||
@kubectl delete -n $(NAMESPACE) secret mysql-$(NAME)config --ignore-not-found
|
||||
18
deploy/kine/nats/ca-csr.json
Normal file
18
deploy/kine/nats/ca-csr.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"CN": "Clastix CA",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"names": [
|
||||
{
|
||||
"C": "IT",
|
||||
"ST": "Italy",
|
||||
"L": "Milan"
|
||||
}
|
||||
],
|
||||
"hosts": [
|
||||
"127.0.0.1",
|
||||
"localhost"
|
||||
]
|
||||
}
|
||||
18
deploy/kine/nats/config.json
Normal file
18
deploy/kine/nats/config.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"signing": {
|
||||
"default": {
|
||||
"expiry": "8760h"
|
||||
},
|
||||
"profiles": {
|
||||
"server": {
|
||||
"expiry": "8760h",
|
||||
"usages": [
|
||||
"signing",
|
||||
"key encipherment",
|
||||
"server auth",
|
||||
"client auth"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
deploy/kine/nats/server-csr.json
Normal file
14
deploy/kine/nats/server-csr.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"CN": "$NAME.$NAMESPACE.svc.cluster.local",
|
||||
"key": {
|
||||
"algo": "rsa",
|
||||
"size": 2048
|
||||
},
|
||||
"hosts": [
|
||||
"127.0.0.1",
|
||||
"localhost",
|
||||
"$NAME-nats",
|
||||
"$NAME-nats.$NAMESPACE.svc",
|
||||
"$NAME-nats.$NAMESPACE.svc.cluster.local"
|
||||
]
|
||||
}
|
||||
14
deploy/kine/nats/values-notls.yaml
Normal file
14
deploy/kine/nats/values-notls.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
config:
|
||||
merge:
|
||||
accounts:
|
||||
private:
|
||||
jetstream: enabled
|
||||
users:
|
||||
- {user: admin, password: "password", permissions: {subscribe: [">"], publish: [">"]}}
|
||||
cluster:
|
||||
enabled: no
|
||||
jetstream:
|
||||
enabled: true
|
||||
fileStore:
|
||||
pvc:
|
||||
size: 32Mi
|
||||
20
deploy/kine/nats/values.yaml
Normal file
20
deploy/kine/nats/values.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
config:
|
||||
merge:
|
||||
accounts:
|
||||
private:
|
||||
jetstream: enabled
|
||||
users:
|
||||
- {user: admin, password: "password", permissions: {subscribe: [">"], publish: [">"]}}
|
||||
cluster:
|
||||
enabled: no
|
||||
nats:
|
||||
tls:
|
||||
enabled: true
|
||||
secretName: nats-$NAME-config
|
||||
cert: server.crt
|
||||
key: server.key
|
||||
jetstream:
|
||||
enabled: true
|
||||
fileStore:
|
||||
pvc:
|
||||
size: 32Mi
|
||||
@@ -1,39 +1,28 @@
|
||||
# Use Alternative Datastores
|
||||
|
||||
Kamaji offers the possibility of having a different storage system than `etcd` thanks to [kine](https://github.com/k3s-io/kine) integration. One of the implementations is [PostgreSQL](https://www.postgresql.org/).
|
||||
Kamaji offers the possibility of having a different storage system than `etcd` thanks to [kine](https://github.com/k3s-io/kine) integration.
|
||||
|
||||
## Install the datastore
|
||||
## Installing Drivers
|
||||
|
||||
On the Management Cluster, install one of the alternative supported datastore:
|
||||
The following `make` recipes help you to setup alternative `Datastore` resources.
|
||||
|
||||
- **MySQL** install it with command:
|
||||
> The default settings are not production grade:
|
||||
> the following scripts are just used to test the Kamaji usage of different drivers.
|
||||
|
||||
`$ make -C deploy/kine/mysql mariadb`
|
||||
On the Management Cluster, you can use the following commands:
|
||||
|
||||
- **PostgreSQL** install it with command:
|
||||
- **MySQL**: `$ make -C deploy/kine/mysql mariadb`
|
||||
|
||||
`$ make -C deploy/kine/postgresql postgresql`
|
||||
- **PostgreSQL**: `$ make -C deploy/kine/postgresql postgresql`
|
||||
|
||||
## Install Cert Manager
|
||||
- **NATS**: `$ make -C deploy/kine/nats nats`
|
||||
|
||||
As prerequisite for Kamaji, install the Cert Manager
|
||||
## Defining a default Datastore upon Kamaji installation
|
||||
|
||||
```bash
|
||||
helm repo add jetstack https://charts.jetstack.io
|
||||
helm repo update
|
||||
helm install \
|
||||
cert-manager jetstack/cert-manager \
|
||||
--namespace cert-manager \
|
||||
--create-namespace \
|
||||
--version v1.11.0 \
|
||||
--set installCRDs=true
|
||||
```
|
||||
Use Helm to install the Kamaji Operator and make sure it uses a datastore with the proper driver `datastore.driver=<MySQL|PostgreSQL|NATS>`.
|
||||
Please refer to the Chart available values for more information on supported options.
|
||||
|
||||
## Install Kamaji
|
||||
|
||||
Use Helm to install the Kamaji Operator and make sure it uses a datastore with the proper driver `datastore.driver=<MySQL|PostgreSQL>`.
|
||||
|
||||
For example, with a PostreSQL datastore installed:
|
||||
For example, with a PostgreSQL datastore installed:
|
||||
|
||||
```bash
|
||||
helm install kamaji charts/kamaji -n kamaji-system --create-namespace \
|
||||
@@ -60,4 +49,19 @@ helm install kamaji charts/kamaji -n kamaji-system --create-namespace \
|
||||
--set datastore.tlsConfig.clientCertificate.privateKey.keyPath=tls.key
|
||||
```
|
||||
|
||||
Once installed, you will able to create Tenant Control Planes using an alternative datastore.
|
||||
Once installed, you will be able to create Tenant Control Planes using an alternative datastore.
|
||||
|
||||
## Defining specific Datastore per Tenant Control Plane
|
||||
|
||||
Each `TenantControlPlane` can refer to a specific `Datastore` thanks to the `/spec/dataStore` field.
|
||||
This allows you to implement your preferred sharding or pooling strategy.
|
||||
|
||||
When the said key is omitted, Kamaji will use the default datastore configured with its CLI argument `--datastore`.
|
||||
|
||||
## NATS considerations
|
||||
|
||||
The NATS support is still experimental, mostly because multi-tenancy is **NOT** supported.
|
||||
|
||||
> A `NATS` based DataStore can host one and only one Tenant Control Plane.
|
||||
> When a `TenantControlPlane` is referring to a NATS `DataStore` already used by another instance,
|
||||
> reconciliation will fail and blocked.
|
||||
|
||||
@@ -99,7 +99,7 @@ The rotation will occur the day before their expiration.
|
||||
> Nota Bene:
|
||||
>
|
||||
> Kamaji is responsible for creating the `etcd` client certificate, and the generation of a new one will occur.
|
||||
> For other Datastore drivers, such as MySQL or PostgreSQL, the referenced Secret will always be deleted by the Controller to trigger the rotation:
|
||||
> For other Datastore drivers, such as MySQL, PostgreSQL, or NATS, the referenced Secret will always be deleted by the Controller to trigger the rotation:
|
||||
> the PKI management, since it's offloaded externally, must provide the renewed certificates.
|
||||
|
||||
## Certificate Authority rotation
|
||||
|
||||
@@ -69,7 +69,9 @@ From the main view, clicking on a Tenant Control Plane row will bring you to the
|
||||

|
||||
|
||||
### Working with Datastore
|
||||
From the menu bar on the left, clicking on the Datastores item, you can access the list of provisioned Datastores. It shows a summary about datastores, including name and the used driver, i.e. etcd, mysql, and postgresql.
|
||||
|
||||
From the menu bar on the left, clicking on the Datastores item, you can access the list of provisioned Datastores.
|
||||
It shows a summary about datastores, including name and the used driver, i.e. `etcd`, `MySQL`, `PostgreSQL`, and `NATS`.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Datastore Migration
|
||||
|
||||
On the Management Cluster, you can deploy one or more multi-tenant datastores as `etcd`, `PostgreSQL`, and `MySQL` to save the state of the Tenant Clusters. A Tenant Control Plane can be migrated from a datastore to another one without service disruption or without complex and error prone backup & restore procedures.
|
||||
On the Management Cluster, you can deploy one or more multi-tenant datastores as `etcd`, `PostgreSQL`, `MySQL`, and `NATS` to save the state of the Tenant Clusters.
|
||||
A Tenant Control Plane can be migrated from a datastore to another one without service disruption or without complex and error-prone backup & restore procedures.
|
||||
|
||||
This guide will assist you to live migrate Tenant's data from a datastore to another one having the same `etcd` driver.
|
||||
|
||||
@@ -80,7 +81,7 @@ helm install dedicated clastix/kamaji-etcd -n dedicated --create-namespace --set
|
||||
You should end up with a new datastore `dedicated` provided by an `etcd` cluster:
|
||||
|
||||
```yaml
|
||||
kubectl get datastore dedicated -o yaml
|
||||
# kubectl get datastore dedicated -o yaml
|
||||
apiVersion: kamaji.clastix.io/v1alpha1
|
||||
kind: DataStore
|
||||
metadata:
|
||||
|
||||
@@ -125,7 +125,7 @@ helm install kamaji clastix/kamaji -n kamaji-system --create-namespace
|
||||
```
|
||||
|
||||
!!! note "A managed datastore is highly recommended in production"
|
||||
The [kamaji-etcd](https://github.com/clastix/kamaji-etcd) project provides the code to setup a multi-tenant `etcd` running as StatefulSet made of three replicas. Optionally, Kamaji offers support for a more robust storage system, as `MySQL` or `PostgreSQL` compatible database, thanks to the native [kine](https://github.com/k3s-io/kine) integration.
|
||||
The [kamaji-etcd](https://github.com/clastix/kamaji-etcd) project provides the code to setup a multi-tenant `etcd` running as StatefulSet made of three replicas. Optionally, Kamaji offers support for a more robust storage system, as `MySQL`, `PostgreSQL`, or `NATS` compatible database, thanks to the native [kine](https://github.com/k3s-io/kine) integration.
|
||||
|
||||
## Create Tenant Cluster
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ DataStoreSpec defines the desired state of DataStore.
|
||||
<td>
|
||||
The driver to use to connect to the shared datastore.<br/>
|
||||
<br/>
|
||||
<i>Enum</i>: etcd, MySQL, PostgreSQL<br/>
|
||||
<i>Enum</i>: etcd, MySQL, PostgreSQL, NATS<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
@@ -100,13 +100,6 @@ DataStoreSpec defines the desired state of DataStore.
|
||||
No need for protocol, just bare IP/FQDN and port.<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespectlsconfig">tlsConfig</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
Defines the TLS/SSL configuration required to connect to the data store in a secure way.<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespecbasicauth">basicAuth</a></b></td>
|
||||
<td>object</td>
|
||||
@@ -115,6 +108,202 @@ No need for protocol, just bare IP/FQDN and port.<br/>
|
||||
This value is optional.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespectlsconfig">tlsConfig</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
This value is optional.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth
|
||||
|
||||
|
||||
|
||||
In case of authentication enabled for the given data store, specifies the username and password pair.
|
||||
This value is optional.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b><a href="#datastorespecbasicauthpassword">password</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespecbasicauthusername">username</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.password
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>content</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Bare content of the file, base64 encoded.
|
||||
It has precedence over the SecretReference value.<br/>
|
||||
<br/>
|
||||
<i>Format</i>: byte<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespecbasicauthpasswordsecretreference">secretReference</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.password.secretReference
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>keyPath</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the key for the given Secret reference where the content is stored.
|
||||
This value is mandatory.<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b>name</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
name is unique within a namespace to reference a secret resource.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>namespace</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
namespace defines the space within which the secret name must be unique.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.username
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>content</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Bare content of the file, base64 encoded.
|
||||
It has precedence over the SecretReference value.<br/>
|
||||
<br/>
|
||||
<i>Format</i>: byte<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespecbasicauthusernamesecretreference">secretReference</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.username.secretReference
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>keyPath</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the key for the given Secret reference where the content is stored.
|
||||
This value is mandatory.<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b>name</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
name is unique within a namespace to reference a secret resource.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>namespace</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
namespace defines the space within which the secret name must be unique.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
@@ -124,6 +313,7 @@ This value is optional.<br/>
|
||||
|
||||
|
||||
Defines the TLS/SSL configuration required to connect to the data store in a secure way.
|
||||
This value is optional.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
@@ -148,7 +338,7 @@ The key reference is required since etcd authentication is based on certificates
|
||||
<td>
|
||||
Specifies the SSL/TLS key and private key pair used to connect to the data store.<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
@@ -493,194 +683,6 @@ It has precedence over the SecretReference value.<br/>
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>keyPath</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the key for the given Secret reference where the content is stored.
|
||||
This value is mandatory.<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b>name</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
name is unique within a namespace to reference a secret resource.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>namespace</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
namespace defines the space within which the secret name must be unique.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth
|
||||
|
||||
|
||||
|
||||
In case of authentication enabled for the given data store, specifies the username and password pair.
|
||||
This value is optional.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b><a href="#datastorespecbasicauthpassword">password</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespecbasicauthusername">username</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.password
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>content</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Bare content of the file, base64 encoded.
|
||||
It has precedence over the SecretReference value.<br/>
|
||||
<br/>
|
||||
<i>Format</i>: byte<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespecbasicauthpasswordsecretreference">secretReference</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.password.secretReference
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>keyPath</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the key for the given Secret reference where the content is stored.
|
||||
This value is mandatory.<br/>
|
||||
</td>
|
||||
<td>true</td>
|
||||
</tr><tr>
|
||||
<td><b>name</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
name is unique within a namespace to reference a secret resource.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>namespace</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
namespace defines the space within which the secret name must be unique.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.username
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>content</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Bare content of the file, base64 encoded.
|
||||
It has precedence over the SecretReference value.<br/>
|
||||
<br/>
|
||||
<i>Format</i>: byte<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#datastorespecbasicauthusernamesecretreference">secretReference</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### DataStore.spec.basicAuth.username.secretReference
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -1038,6 +1040,13 @@ Selector which must match a node's labels for the pod to be scheduled on that no
|
||||
More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#tenantcontrolplanespeccontrolplanedeploymentpodadditionalmetadata">podAdditionalMetadata</a></b></td>
|
||||
<td>object</td>
|
||||
<td>
|
||||
AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#tenantcontrolplanespeccontrolplanedeploymentregistrysettings">registrySettings</a></b></td>
|
||||
<td>object</td>
|
||||
@@ -1077,6 +1086,15 @@ empty definition that uses the default runtime handler.
|
||||
More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>serviceAccountName</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
ServiceAccountName allows to specify the service account to be mounted to the pods of the Control plane deployment<br/>
|
||||
<br/>
|
||||
<i>Default</i>: default<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#tenantcontrolplanespeccontrolplanedeploymentstrategy">strategy</a></b></td>
|
||||
<td>object</td>
|
||||
@@ -1511,8 +1529,14 @@ Selects a key of a ConfigMap.
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -1628,8 +1652,14 @@ Selects a key of a secret in the pod's namespace
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -1703,8 +1733,14 @@ The ConfigMap to select from
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -1738,8 +1774,14 @@ The Secret to select from
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -4328,8 +4370,14 @@ Selects a key of a ConfigMap.
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -4445,8 +4493,14 @@ Selects a key of a secret in the pod's namespace
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -4520,8 +4574,14 @@ The ConfigMap to select from
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -4555,8 +4615,14 @@ The Secret to select from
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -7647,8 +7713,14 @@ More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -7731,8 +7803,14 @@ to OpenStack.
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -7787,8 +7865,14 @@ relative and may not contain the '..' path or start with '..'.<br/>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -7939,8 +8023,14 @@ secret object contains more than one secret, all secret references are passed.
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -8819,8 +8909,14 @@ scripts.
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -9188,8 +9284,14 @@ secretRef is the CHAP Secret for iSCSI target and initiator authentication
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -9660,8 +9762,14 @@ relative and may not contain the '..' path or start with '..'.<br/>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -9913,8 +10021,14 @@ relative and may not contain the '..' path or start with '..'.<br/>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
@@ -10212,8 +10326,14 @@ More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -10337,8 +10457,14 @@ sensitive information. If this is not provided, Login operation will fail.
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -10543,8 +10669,14 @@ credentials. If not specified, default values will be attempted.
|
||||
<td>string</td>
|
||||
<td>
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?<br/>
|
||||
TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: <br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
@@ -12246,6 +12378,39 @@ Only modify if you know what you are doing.
|
||||
</table>
|
||||
|
||||
|
||||
### TenantControlPlane.spec.controlPlane.deployment.podAdditionalMetadata
|
||||
|
||||
|
||||
|
||||
AdditionalMetadata defines which additional metadata, such as labels and annotations, must be attached to the created resource.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>annotations</b></td>
|
||||
<td>map[string]string</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>labels</b></td>
|
||||
<td>map[string]string</td>
|
||||
<td>
|
||||
<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### TenantControlPlane.spec.controlPlane.deployment.registrySettings
|
||||
|
||||
|
||||
@@ -13394,6 +13559,16 @@ unxpected ways. Only modify if you know what you are doing.<br/>
|
||||
<i>Default</i>: registry.k8s.io/kas-network-proxy/proxy-agent<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b><a href="#tenantcontrolplanespecaddonskonnectivityagenttolerationsindex">tolerations</a></b></td>
|
||||
<td>[]object</td>
|
||||
<td>
|
||||
Tolerations for the deployed agent.
|
||||
Can be customized to start the konnectivity-agent even if the nodes are not ready or tainted.<br/>
|
||||
<br/>
|
||||
<i>Default</i>: [map[key:CriticalAddonsOnly operator:Exists]]<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>version</b></td>
|
||||
<td>string</td>
|
||||
@@ -13407,6 +13582,72 @@ unxpected ways. Only modify if you know what you are doing.<br/>
|
||||
</table>
|
||||
|
||||
|
||||
### TenantControlPlane.spec.addons.konnectivity.agent.tolerations[index]
|
||||
|
||||
|
||||
|
||||
The pod this Toleration is attached to tolerates any taint that matches
|
||||
the triple <key,value,effect> using the matching operator <operator>.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr>
|
||||
<td><b>effect</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Effect indicates the taint effect to match. Empty means match all taint effects.
|
||||
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>key</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Key is the taint key that the toleration applies to. Empty means match all taint keys.
|
||||
If the key is empty, operator must be Exists; this combination means to match all values and all keys.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>operator</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Operator represents a key's relationship to the value.
|
||||
Valid operators are Exists and Equal. Defaults to Equal.
|
||||
Exists is equivalent to wildcard for value, so that a pod can
|
||||
tolerate all taints of a particular category.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>tolerationSeconds</b></td>
|
||||
<td>integer</td>
|
||||
<td>
|
||||
TolerationSeconds represents the period of time the toleration (which must be
|
||||
of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,
|
||||
it is not set, which means tolerate the taint forever (do not evict). Zero and
|
||||
negative values will be treated as 0 (evict immediately) by the system.<br/>
|
||||
<br/>
|
||||
<i>Format</i>: int64<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr><tr>
|
||||
<td><b>value</b></td>
|
||||
<td>string</td>
|
||||
<td>
|
||||
Value is the taint value the toleration matches to.
|
||||
If the operator is Exists, the value should be empty, otherwise just a regular string.<br/>
|
||||
</td>
|
||||
<td>false</td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
|
||||
|
||||
### TenantControlPlane.spec.addons.konnectivity.server
|
||||
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -18,3 +18,4 @@ In Kamaji, there are different components that might require independent version
|
||||
| v0.4.1 | v1.22+ | [v1.21.0 .. v1.29.1] |
|
||||
| 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] |
|
||||
|
||||
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
|
||||
|
||||
74
e2e/tcp_custom_sa_test.go
Normal file
74
e2e/tcp_custom_sa_test.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
pointer "k8s.io/utils/ptr"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
var _ = Describe("Deploy a TenantControlPlane with resource with custom service account", func() {
|
||||
// service account object
|
||||
sa := &corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
// Fill TenantControlPlane object
|
||||
tcp := &kamajiv1alpha1.TenantControlPlane{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "tcp-clusterip-customsa",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
|
||||
ControlPlane: kamajiv1alpha1.ControlPlane{
|
||||
Deployment: kamajiv1alpha1.DeploymentSpec{
|
||||
Replicas: pointer.To(int32(1)),
|
||||
ServiceAccountName: sa.GetName(),
|
||||
},
|
||||
Service: kamajiv1alpha1.ServiceSpec{
|
||||
ServiceType: "ClusterIP",
|
||||
},
|
||||
},
|
||||
NetworkProfile: kamajiv1alpha1.NetworkProfileSpec{
|
||||
Address: "172.18.0.2",
|
||||
},
|
||||
Kubernetes: kamajiv1alpha1.KubernetesSpec{
|
||||
Version: "v1.23.6",
|
||||
Kubelet: kamajiv1alpha1.KubeletSpec{
|
||||
CGroupFS: "cgroupfs",
|
||||
},
|
||||
AdmissionControllers: kamajiv1alpha1.AdmissionControllers{
|
||||
"LimitRanger",
|
||||
"ResourceQuota",
|
||||
},
|
||||
},
|
||||
Addons: kamajiv1alpha1.AddonsSpec{},
|
||||
},
|
||||
}
|
||||
|
||||
// Create service account and TenantControlPlane resources into the cluster
|
||||
JustBeforeEach(func() {
|
||||
Expect(k8sClient.Create(context.Background(), sa)).NotTo(HaveOccurred())
|
||||
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
// Delete the service account and TenantControlPlane resources after test is finished
|
||||
JustAfterEach(func() {
|
||||
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
|
||||
})
|
||||
// Check if TenantControlPlane resource has been created and if its pods have the right service account
|
||||
It("Should be Ready and have correct sa", func() {
|
||||
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
|
||||
PodsServiceAccountMustEqualTo(tcp, sa)
|
||||
})
|
||||
})
|
||||
54
e2e/tcp_nats_ready_no_tls_test.go
Normal file
54
e2e/tcp_nats_ready_no_tls_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
pointer "k8s.io/utils/ptr"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
var _ = Describe("Deploy a TenantControlPlane resource with the NATS driver without TLS", func() {
|
||||
// Fill TenantControlPlane object
|
||||
tcp := &kamajiv1alpha1.TenantControlPlane{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "nats-notls",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
|
||||
DataStore: "nats-notls",
|
||||
ControlPlane: kamajiv1alpha1.ControlPlane{
|
||||
Deployment: kamajiv1alpha1.DeploymentSpec{
|
||||
Replicas: pointer.To(int32(1)),
|
||||
},
|
||||
Service: kamajiv1alpha1.ServiceSpec{
|
||||
ServiceType: "ClusterIP",
|
||||
},
|
||||
},
|
||||
Kubernetes: kamajiv1alpha1.KubernetesSpec{
|
||||
Version: "v1.23.6",
|
||||
Kubelet: kamajiv1alpha1.KubeletSpec{
|
||||
CGroupFS: "cgroupfs",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// Create a TenantControlPlane resource into the cluster
|
||||
JustBeforeEach(func() {
|
||||
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
|
||||
})
|
||||
// Delete the TenantControlPlane resource after test is finished
|
||||
JustAfterEach(func() {
|
||||
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
|
||||
})
|
||||
// Check if TenantControlPlane resource has been created
|
||||
It("Should be Ready", func() {
|
||||
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
|
||||
})
|
||||
})
|
||||
54
e2e/tcp_nats_ready_test.go
Normal file
54
e2e/tcp_nats_ready_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
pointer "k8s.io/utils/ptr"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
var _ = Describe("Deploy a TenantControlPlane resource with the NATS driver", func() {
|
||||
// Fill TenantControlPlane object
|
||||
tcp := &kamajiv1alpha1.TenantControlPlane{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "nats",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
|
||||
DataStore: "nats-bronze",
|
||||
ControlPlane: kamajiv1alpha1.ControlPlane{
|
||||
Deployment: kamajiv1alpha1.DeploymentSpec{
|
||||
Replicas: pointer.To(int32(1)),
|
||||
},
|
||||
Service: kamajiv1alpha1.ServiceSpec{
|
||||
ServiceType: "ClusterIP",
|
||||
},
|
||||
},
|
||||
Kubernetes: kamajiv1alpha1.KubernetesSpec{
|
||||
Version: "v1.23.6",
|
||||
Kubelet: kamajiv1alpha1.KubeletSpec{
|
||||
CGroupFS: "cgroupfs",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
// Create a TenantControlPlane resource into the cluster
|
||||
JustBeforeEach(func() {
|
||||
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
|
||||
})
|
||||
// Delete the TenantControlPlane resource after test is finished
|
||||
JustAfterEach(func() {
|
||||
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
|
||||
})
|
||||
// Check if TenantControlPlane resource has been created
|
||||
It("Should be Ready", func() {
|
||||
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
|
||||
})
|
||||
})
|
||||
78
e2e/tcp_pod_additional_metadata_test.go
Normal file
78
e2e/tcp_pod_additional_metadata_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
pointer "k8s.io/utils/ptr"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
var _ = Describe("Deploy a TenantControlPlane resource with additional pod metadata", func() {
|
||||
// Fill TenantControlPlane object
|
||||
tcp := &kamajiv1alpha1.TenantControlPlane{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "tcp-clusterip-additional-metadata",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: kamajiv1alpha1.TenantControlPlaneSpec{
|
||||
ControlPlane: kamajiv1alpha1.ControlPlane{
|
||||
Deployment: kamajiv1alpha1.DeploymentSpec{
|
||||
Replicas: pointer.To(int32(1)),
|
||||
PodAdditionalMetadata: kamajiv1alpha1.AdditionalMetadata{
|
||||
Labels: map[string]string{
|
||||
"hello-label": "world",
|
||||
"foo-label": "bar",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"hello-ann": "world",
|
||||
"foo-ann": "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
Service: kamajiv1alpha1.ServiceSpec{
|
||||
ServiceType: "ClusterIP",
|
||||
},
|
||||
},
|
||||
NetworkProfile: kamajiv1alpha1.NetworkProfileSpec{
|
||||
Address: "172.18.0.2",
|
||||
},
|
||||
Kubernetes: kamajiv1alpha1.KubernetesSpec{
|
||||
Version: "v1.23.6",
|
||||
Kubelet: kamajiv1alpha1.KubeletSpec{
|
||||
CGroupFS: "cgroupfs",
|
||||
},
|
||||
AdmissionControllers: kamajiv1alpha1.AdmissionControllers{
|
||||
"LimitRanger",
|
||||
"ResourceQuota",
|
||||
},
|
||||
},
|
||||
Addons: kamajiv1alpha1.AddonsSpec{},
|
||||
},
|
||||
}
|
||||
|
||||
// Create a TenantControlPlane resource into the cluster
|
||||
JustBeforeEach(func() {
|
||||
Expect(k8sClient.Create(context.Background(), tcp)).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
// Delete the TenantControlPlane resource after test is finished
|
||||
JustAfterEach(func() {
|
||||
Expect(k8sClient.Delete(context.Background(), tcp)).Should(Succeed())
|
||||
})
|
||||
|
||||
// Check if TenantControlPlane resource has been created
|
||||
It("Should be Ready with expected additional metadata", func() {
|
||||
StatusMustEqualTo(tcp, kamajiv1alpha1.VersionReady)
|
||||
AllPodsLabelMustEqualTo(tcp, "hello-label", "world")
|
||||
AllPodsLabelMustEqualTo(tcp, "foo-label", "bar")
|
||||
AllPodsAnnotationMustEqualTo(tcp, "hello-ann", "world")
|
||||
AllPodsAnnotationMustEqualTo(tcp, "foo-ann", "bar")
|
||||
})
|
||||
})
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
@@ -136,3 +137,61 @@ func StatusMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, status kamajiv1al
|
||||
return *tcp.Status.Kubernetes.Version.Status
|
||||
}, 5*time.Minute, time.Second).Should(Equal(status))
|
||||
}
|
||||
|
||||
func AllPodsLabelMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, label string, value string) {
|
||||
Eventually(func() bool {
|
||||
tcpPods := &corev1.PodList{}
|
||||
err := k8sClient.List(context.Background(), tcpPods, client.MatchingLabels{
|
||||
"kamaji.clastix.io/name": tcp.GetName(),
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, pod := range tcpPods.Items {
|
||||
if pod.Labels[label] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}, 5*time.Minute, time.Second).Should(BeTrue())
|
||||
}
|
||||
|
||||
func AllPodsAnnotationMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, annotation string, value string) {
|
||||
Eventually(func() bool {
|
||||
tcpPods := &corev1.PodList{}
|
||||
err := k8sClient.List(context.Background(), tcpPods, client.MatchingLabels{
|
||||
"kamaji.clastix.io/name": tcp.GetName(),
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, pod := range tcpPods.Items {
|
||||
if pod.Annotations[annotation] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}, 5*time.Minute, time.Second).Should(BeTrue())
|
||||
}
|
||||
|
||||
func PodsServiceAccountMustEqualTo(tcp *kamajiv1alpha1.TenantControlPlane, sa *corev1.ServiceAccount) {
|
||||
saName := sa.GetName()
|
||||
Eventually(func() bool {
|
||||
tcpPods := &corev1.PodList{}
|
||||
err := k8sClient.List(context.Background(), tcpPods, client.MatchingLabels{
|
||||
"kamaji.clastix.io/name": tcp.GetName(),
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, pod := range tcpPods.Items {
|
||||
if pod.Spec.ServiceAccountName != saName {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}, 5*time.Minute, time.Second).Should(BeTrue())
|
||||
}
|
||||
|
||||
89
go.mod
89
go.mod
@@ -7,17 +7,19 @@ 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/clastix/kamaji-telemetry v1.0.0
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/go-pg/pg/v10 v10.10.6
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
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/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
|
||||
@@ -25,16 +27,16 @@ require (
|
||||
go.etcd.io/etcd/client/v3 v3.5.10
|
||||
go.uber.org/automaxprocs v1.5.1
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||
k8s.io/api v0.30.0
|
||||
k8s.io/apimachinery v0.30.0
|
||||
k8s.io/apiserver v0.30.0
|
||||
k8s.io/client-go v0.30.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/kubelet v0.0.0
|
||||
k8s.io/kubernetes v1.30.0
|
||||
k8s.io/kubernetes v1.30.2
|
||||
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 (
|
||||
@@ -84,6 +86,7 @@ require (
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9 // indirect
|
||||
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
|
||||
@@ -98,6 +101,8 @@ require (
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
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
|
||||
@@ -124,14 +129,14 @@ require (
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/crypto v0.21.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.18.0 // indirect
|
||||
golang.org/x/term v0.18.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
|
||||
@@ -146,9 +151,9 @@ require (
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.30.0 // indirect
|
||||
k8s.io/cli-runtime v0.30.0 // indirect
|
||||
k8s.io/component-base v0.30.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.30.1 // indirect
|
||||
k8s.io/cli-runtime v0.30.1 // indirect
|
||||
k8s.io/component-base v0.30.2 // indirect
|
||||
k8s.io/component-helpers v0.0.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
|
||||
k8s.io/kube-proxy v0.0.0 // indirect
|
||||
@@ -162,33 +167,33 @@ require (
|
||||
)
|
||||
|
||||
replace (
|
||||
k8s.io/api => k8s.io/api v0.30.0
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.30.0
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.30.0
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.30.0
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.30.0
|
||||
k8s.io/client-go => k8s.io/client-go v0.30.0
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.30.0
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.30.0
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.30.0
|
||||
k8s.io/component-base => k8s.io/component-base v0.30.0
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.30.0
|
||||
k8s.io/controller-manager => k8s.io/controller-manager v0.30.0
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.30.0
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.30.0
|
||||
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.30.0
|
||||
k8s.io/endpointslice => k8s.io/endpointslice v0.30.0
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.30.0
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.30.0
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.30.0
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.30.0
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.30.0
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.30.0
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.30.0
|
||||
k8s.io/metrics => k8s.io/metrics v0.30.0
|
||||
k8s.io/mount-utils => k8s.io/mount-utils v0.30.0
|
||||
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.30.0
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.30.0
|
||||
k8s.io/api => k8s.io/api v0.30.2
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.30.2
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.30.2
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.30.2
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.30.2
|
||||
k8s.io/client-go => k8s.io/client-go v0.30.2
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.30.2
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.30.2
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.30.2
|
||||
k8s.io/component-base => k8s.io/component-base v0.30.2
|
||||
k8s.io/component-helpers => k8s.io/component-helpers v0.30.2
|
||||
k8s.io/controller-manager => k8s.io/controller-manager v0.30.2
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.30.2
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.30.2
|
||||
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.30.2
|
||||
k8s.io/endpointslice => k8s.io/endpointslice v0.30.2
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.30.2
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.30.2
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.30.2
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.30.2
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.30.2
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.30.2
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.30.2
|
||||
k8s.io/metrics => k8s.io/metrics v0.30.2
|
||||
k8s.io/mount-utils => k8s.io/mount-utils v0.30.2
|
||||
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.30.2
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.30.2
|
||||
)
|
||||
|
||||
replace github.com/JamesStewy/go-mysqldump => github.com/vtoma/go-mysqldump v1.0.0
|
||||
|
||||
88
go.sum
88
go.sum
@@ -861,6 +861,8 @@ github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLI
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/clastix/kamaji-telemetry v1.0.0 h1:/s7TVsyQpunD+cBKIaWmZ1yCXXYXgf4uQ4TeXio4moY=
|
||||
github.com/clastix/kamaji-telemetry v1.0.0/go.mod h1:yhK/I0qEmKQw4mtEZRUnQfjsbbrIZtuR/XXISBrrETU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -992,6 +994,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||
@@ -1106,8 +1109,9 @@ github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||
@@ -1250,8 +1254,9 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
@@ -1275,8 +1280,9 @@ github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
|
||||
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
@@ -1378,6 +1384,8 @@ github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j
|
||||
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
|
||||
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -1469,6 +1477,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4=
|
||||
github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
|
||||
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
@@ -1684,8 +1698,9 @@ github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKv
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
@@ -1873,8 +1888,9 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -2222,8 +2238,9 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -2243,8 +2260,9 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -2740,25 +2758,25 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||
k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA=
|
||||
k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE=
|
||||
k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs=
|
||||
k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y=
|
||||
k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA=
|
||||
k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
||||
k8s.io/apiserver v0.30.0 h1:QCec+U72tMQ+9tR6A0sMBB5Vh6ImCEkoKkTDRABWq6M=
|
||||
k8s.io/apiserver v0.30.0/go.mod h1:smOIBq8t0MbKZi7O7SyIpjPsiKJ8qa+llcFCluKyqiY=
|
||||
k8s.io/cli-runtime v0.30.0 h1:0vn6/XhOvn1RJ2KJOC6IRR2CGqrpT6QQF4+8pYpWQ48=
|
||||
k8s.io/cli-runtime v0.30.0/go.mod h1:vATpDMATVTMA79sZ0YUCzlMelf6rUjoBzlp+RnoM+cg=
|
||||
k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ=
|
||||
k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY=
|
||||
k8s.io/cluster-bootstrap v0.30.0 h1:vaIjA1eMFpcLYz+p6NMj75aqiauDahFx9EkuTxc0GMI=
|
||||
k8s.io/cluster-bootstrap v0.30.0/go.mod h1:/ceTq+EC/aOrQk27mfmFW/iOeQDqzKg6vYWIBFNHSAE=
|
||||
k8s.io/component-base v0.30.0 h1:cj6bp38g0ainlfYtaOQuRELh5KSYjhKxM+io7AUIk4o=
|
||||
k8s.io/component-base v0.30.0/go.mod h1:V9x/0ePFNaKeKYA3bOvIbrNoluTSG+fSJKjLdjOoeXQ=
|
||||
k8s.io/component-helpers v0.30.0 h1:xbJtNCfSM4SB/Tz5JqCKDZv4eT5LVi/AWQ1VOxhmStU=
|
||||
k8s.io/component-helpers v0.30.0/go.mod h1:68HlSwXIumMKmCx8cZe1PoafQEYh581/sEpxMrkhmX4=
|
||||
k8s.io/cri-api v0.30.0/go.mod h1://4/umPJSW1ISNSNng4OwjpkvswJOQwU8rnkvO8P+xg=
|
||||
k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
|
||||
k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
|
||||
k8s.io/apiextensions-apiserver v0.30.2 h1:l7Eue2t6QiLHErfn2vwK4KgF4NeDgjQkCXtEbOocKIE=
|
||||
k8s.io/apiextensions-apiserver v0.30.2/go.mod h1:lsJFLYyK40iguuinsb3nt+Sj6CmodSI4ACDLep1rgjw=
|
||||
k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
|
||||
k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
|
||||
k8s.io/apiserver v0.30.2 h1:ACouHiYl1yFI2VFI3YGM+lvxgy6ir4yK2oLOsLI1/tw=
|
||||
k8s.io/apiserver v0.30.2/go.mod h1:BOTdFBIch9Sv0ypSEcUR6ew/NUFGocRFNl72Ra7wTm8=
|
||||
k8s.io/cli-runtime v0.30.2 h1:ooM40eEJusbgHNEqnHziN9ZpLN5U4WcQGsdLKVxpkKE=
|
||||
k8s.io/cli-runtime v0.30.2/go.mod h1:Y4g/2XezFyTATQUbvV5WaChoUGhojv/jZAtdp5Zkm0A=
|
||||
k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
|
||||
k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
|
||||
k8s.io/cluster-bootstrap v0.30.2 h1:9PQ5phjWTxmPFKPEzTG6QJzPaUIfuW2RqcHDME5gqPg=
|
||||
k8s.io/cluster-bootstrap v0.30.2/go.mod h1:dvzAgNVmwRfZ0BzHI/WTvzqlzmNH7w21mdnahEq61KY=
|
||||
k8s.io/component-base v0.30.2 h1:pqGBczYoW1sno8q9ObExUqrYSKhtE5rW3y6gX88GZII=
|
||||
k8s.io/component-base v0.30.2/go.mod h1:yQLkQDrkK8J6NtP+MGJOws+/PPeEXNpwFixsUI7h/OE=
|
||||
k8s.io/component-helpers v0.30.2 h1:kDMYLiWEYeWU7H6jBI+Ua1i2hqNh0DzqDHNIppFC3po=
|
||||
k8s.io/component-helpers v0.30.2/go.mod h1:tI0anfS6AbRqooaICkGg7UVAQLedOauVSQW9srDBnJw=
|
||||
k8s.io/cri-api v0.30.2/go.mod h1://4/umPJSW1ISNSNng4OwjpkvswJOQwU8rnkvO8P+xg=
|
||||
k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
@@ -2766,16 +2784,16 @@ k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
|
||||
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kms v0.30.0/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4=
|
||||
k8s.io/kms v0.30.2/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
|
||||
k8s.io/kube-proxy v0.30.0 h1:j+09l13SKeGIHEdU+kiOvUjKpqI82S9sGcBFiqC7EJw=
|
||||
k8s.io/kube-proxy v0.30.0/go.mod h1:0Dx6+2DKq73P7RaJaElqwZQ3L02TnCVvU+EaWicnI/s=
|
||||
k8s.io/kubelet v0.30.0 h1:/pqHVR2Rn8ExCpn211wL3pMtqRFpcBcJPl4+1INbIMk=
|
||||
k8s.io/kubelet v0.30.0/go.mod h1:WukdKqbQxnj+csn3K8XOKeX7Sh60J/da25IILjvvB5s=
|
||||
k8s.io/kube-proxy v0.30.2 h1:rBLnKQzXO5u2KO7t3rqYkHf5/oG46ZjqcqfEUw4yOEs=
|
||||
k8s.io/kube-proxy v0.30.2/go.mod h1:7qE0iyUFIi0FJZNO6fe/Eif17RKckTntEl2gjxsta+0=
|
||||
k8s.io/kubelet v0.30.2 h1:Ck4E/pHndI20IzDXxS57dElhDGASPO5pzXF7BcKfmCY=
|
||||
k8s.io/kubelet v0.30.2/go.mod h1:DSwwTbLQmdNkebAU7ypIALR4P9aXZNFwgRmedojUE94=
|
||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
k8s.io/kubernetes v1.30.0 h1:u3Yw8rNlo2NDSGaDpoxoHXLPQnEu1tfqHATKOJe94HY=
|
||||
k8s.io/kubernetes v1.30.0/go.mod h1:yPbIk3MhmhGigX62FLJm+CphNtjxqCvAIFQXup6RKS0=
|
||||
k8s.io/kubernetes v1.30.2 h1:11WhS78OYX/lnSy6TXxPO6Hk+E5K9ZNrEsk9JgMSX8I=
|
||||
k8s.io/kubernetes v1.30.2/go.mod h1:yPbIk3MhmhGigX62FLJm+CphNtjxqCvAIFQXup6RKS0=
|
||||
k8s.io/system-validators v1.8.0 h1:tq05tdO9zdJZnNF3SXrq6LE7Knc/KfJm5wk68467JDg=
|
||||
k8s.io/system-validators v1.8.0/go.mod h1:gP1Ky+R9wtrSiFbrpEPwWMeYz9yqyy1S/KOh0Vci7WI=
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
@@ -2840,8 +2858,8 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.29.0/go.mod h1:z7+wmGM2dfIiLRfrC6jb5kV2Mq/sK1ZP303cxzkV5Y4=
|
||||
sigs.k8s.io/controller-runtime v0.17.1-0.20240416095710-67b27f27e514 h1:jHkHzzQ/HXBagSiTfTnfGVdPhE7O0jC7QRXDZ9MK4Xg=
|
||||
sigs.k8s.io/controller-runtime v0.17.1-0.20240416095710-67b27f27e514/go.mod h1:TLM3OvUJgcqHVBLVRlNylmfbOlOukMLFHtc6jo3EtIQ=
|
||||
sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw=
|
||||
sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
|
||||
|
||||
@@ -61,7 +61,8 @@ func (d Deployment) Build(ctx context.Context, deployment *appsv1.Deployment, te
|
||||
|
||||
d.setLabels(deployment, utilities.MergeMaps(utilities.KamajiLabels(tenantControlPlane.GetName(), "deployment"), tenantControlPlane.Spec.ControlPlane.Deployment.AdditionalMetadata.Labels))
|
||||
d.setAnnotations(deployment, utilities.MergeMaps(deployment.Annotations, tenantControlPlane.Spec.ControlPlane.Deployment.AdditionalMetadata.Annotations))
|
||||
d.setTemplateLabels(&deployment.Spec.Template, d.templateLabels(ctx, &tenantControlPlane))
|
||||
d.setTemplateLabels(&deployment.Spec.Template, utilities.MergeMaps(d.templateLabels(ctx, &tenantControlPlane), tenantControlPlane.Spec.ControlPlane.Deployment.PodAdditionalMetadata.Labels))
|
||||
d.setTemplateAnnotations(&deployment.Spec.Template, tenantControlPlane.Spec.ControlPlane.Deployment.PodAdditionalMetadata.Annotations)
|
||||
d.setNodeSelector(&deployment.Spec.Template.Spec, tenantControlPlane)
|
||||
d.setToleration(&deployment.Spec.Template.Spec, tenantControlPlane)
|
||||
d.setAffinity(&deployment.Spec.Template.Spec, tenantControlPlane)
|
||||
@@ -76,6 +77,7 @@ func (d Deployment) Build(ctx context.Context, deployment *appsv1.Deployment, te
|
||||
d.setContainers(&deployment.Spec.Template.Spec, tenantControlPlane, address)
|
||||
d.setAdditionalVolumes(&deployment.Spec.Template.Spec, tenantControlPlane)
|
||||
d.setVolumes(&deployment.Spec.Template.Spec, tenantControlPlane)
|
||||
d.setServiceAccount(&deployment.Spec.Template.Spec, tenantControlPlane)
|
||||
d.Client.Scheme().Default(deployment)
|
||||
}
|
||||
|
||||
@@ -708,7 +710,7 @@ func (d Deployment) buildKubeAPIServerCommand(tenantControlPlane kamajiv1alpha1.
|
||||
}
|
||||
|
||||
switch d.DataStore.Spec.Driver {
|
||||
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver:
|
||||
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver, kamajiv1alpha1.KineNatsDriver:
|
||||
desiredArgs["--etcd-servers"] = "http://127.0.0.1:2379"
|
||||
case kamajiv1alpha1.EtcdDriver:
|
||||
httpsEndpoints := make([]string, 0, len(d.DataStore.Spec.Endpoints))
|
||||
@@ -803,7 +805,10 @@ func (d Deployment) removeKineContainers(podSpec *corev1.PodSpec) {
|
||||
|
||||
podSpec.Containers = containers
|
||||
}
|
||||
// Removing the kine init-container, if present
|
||||
d.removeKineInitContainers(podSpec)
|
||||
}
|
||||
|
||||
func (d Deployment) removeKineInitContainers(podSpec *corev1.PodSpec) {
|
||||
if found, index := utilities.HasNamedContainer(podSpec.InitContainers, kineInitContainerName); found {
|
||||
var initContainers []corev1.Container
|
||||
|
||||
@@ -821,45 +826,67 @@ func (d Deployment) buildKine(podSpec *corev1.PodSpec, tcp kamajiv1alpha1.Tenant
|
||||
|
||||
return
|
||||
}
|
||||
// Ensuring the init container required for kine is present:
|
||||
// a chmod is required for kine in order to read the certificates to connect to the secured datastore.
|
||||
found, index := utilities.HasNamedContainer(podSpec.InitContainers, kineInitContainerName)
|
||||
if !found {
|
||||
index = len(podSpec.InitContainers)
|
||||
podSpec.InitContainers = append(podSpec.InitContainers, corev1.Container{})
|
||||
|
||||
// Building kine arguments, taking in consideration the user-space ones if provided.
|
||||
args := map[string]string{}
|
||||
|
||||
if d.DataStore.Spec.TLSConfig != nil {
|
||||
// Ensuring the init container required for kine is present:
|
||||
// a chmod is required for kine in order to read the certificates to connect to the secured datastore.
|
||||
found, index := utilities.HasNamedContainer(podSpec.InitContainers, kineInitContainerName)
|
||||
if !found {
|
||||
index = len(podSpec.InitContainers)
|
||||
podSpec.InitContainers = append(podSpec.InitContainers, corev1.Container{})
|
||||
}
|
||||
|
||||
podSpec.InitContainers[index].Name = kineInitContainerName
|
||||
podSpec.InitContainers[index].Image = d.KineContainerImage
|
||||
podSpec.InitContainers[index].Command = []string{"sh"}
|
||||
|
||||
podSpec.InitContainers[index].Args = []string{
|
||||
"-c",
|
||||
"cp /kine/*.* /certs && chmod -R 600 /certs/*.*",
|
||||
}
|
||||
|
||||
podSpec.InitContainers[index].VolumeMounts = []corev1.VolumeMount{
|
||||
{
|
||||
Name: dataStoreCertsVolumeName,
|
||||
ReadOnly: true,
|
||||
MountPath: "/kine",
|
||||
},
|
||||
{
|
||||
Name: kineVolumeCertName,
|
||||
MountPath: "/certs",
|
||||
ReadOnly: false,
|
||||
},
|
||||
}
|
||||
|
||||
args["--ca-file"] = "/certs/ca.crt"
|
||||
|
||||
if d.DataStore.Spec.TLSConfig.ClientCertificate != nil {
|
||||
args["--cert-file"] = "/certs/server.crt"
|
||||
args["--key-file"] = "/certs/server.key"
|
||||
}
|
||||
} else {
|
||||
// if no TLS configuration is provided, the kine initContainer must be removed.
|
||||
d.removeKineInitContainers(podSpec)
|
||||
}
|
||||
|
||||
podSpec.InitContainers[index].Name = kineInitContainerName
|
||||
podSpec.InitContainers[index].Image = d.KineContainerImage
|
||||
podSpec.InitContainers[index].Command = []string{"sh"}
|
||||
podSpec.InitContainers[index].Args = []string{
|
||||
"-c",
|
||||
"cp /kine/*.* /certs && chmod -R 600 /certs/*.*",
|
||||
}
|
||||
podSpec.InitContainers[index].VolumeMounts = []corev1.VolumeMount{
|
||||
{
|
||||
Name: dataStoreCertsVolumeName,
|
||||
ReadOnly: true,
|
||||
MountPath: "/kine",
|
||||
},
|
||||
{
|
||||
Name: kineVolumeCertName,
|
||||
MountPath: "/certs",
|
||||
ReadOnly: false,
|
||||
},
|
||||
}
|
||||
// Kine is expecting an additional container, and it must be removed before proceeding with the additional one
|
||||
// in order to make this function idempotent.
|
||||
found, index = utilities.HasNamedContainer(podSpec.Containers, kineContainerName)
|
||||
found, index := utilities.HasNamedContainer(podSpec.Containers, kineContainerName)
|
||||
if !found {
|
||||
index = len(podSpec.Containers)
|
||||
podSpec.Containers = append(podSpec.Containers, corev1.Container{})
|
||||
}
|
||||
// Building kine arguments, taking in consideration the user-space ones if provided.
|
||||
args := map[string]string{}
|
||||
|
||||
if tcp.Spec.ControlPlane.Deployment.ExtraArgs != nil {
|
||||
args = utilities.ArgsFromSliceToMap(tcp.Spec.ControlPlane.Deployment.ExtraArgs.Kine)
|
||||
utilArgs := utilities.ArgsFromSliceToMap(tcp.Spec.ControlPlane.Deployment.ExtraArgs.Kine)
|
||||
|
||||
// Merging the user-space arguments with the Kamaji ones.
|
||||
for k, v := range utilArgs {
|
||||
args[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
switch d.DataStore.Spec.Driver {
|
||||
@@ -867,12 +894,10 @@ func (d Deployment) buildKine(podSpec *corev1.PodSpec, tcp kamajiv1alpha1.Tenant
|
||||
args["--endpoint"] = "mysql://$(DB_USER):$(DB_PASSWORD)@tcp($(DB_CONNECTION_STRING))/$(DB_SCHEMA)"
|
||||
case kamajiv1alpha1.KinePostgreSQLDriver:
|
||||
args["--endpoint"] = "postgres://$(DB_USER):$(DB_PASSWORD)@$(DB_CONNECTION_STRING)/$(DB_SCHEMA)"
|
||||
case kamajiv1alpha1.KineNatsDriver:
|
||||
args["--endpoint"] = "nats://$(DB_USER):$(DB_PASSWORD)@$(DB_CONNECTION_STRING)?bucket=$(DB_SCHEMA)&noEmbed"
|
||||
}
|
||||
|
||||
args["--ca-file"] = "/certs/ca.crt"
|
||||
args["--cert-file"] = "/certs/server.crt"
|
||||
args["--key-file"] = "/certs/server.key"
|
||||
|
||||
podSpec.Containers[index].Name = kineContainerName
|
||||
podSpec.Containers[index].Image = d.KineContainerImage
|
||||
podSpec.Containers[index].Command = []string{"/bin/kine"}
|
||||
@@ -999,6 +1024,10 @@ func (d Deployment) setTemplateLabels(template *corev1.PodTemplateSpec, labels m
|
||||
template.SetLabels(labels)
|
||||
}
|
||||
|
||||
func (d Deployment) setTemplateAnnotations(template *corev1.PodTemplateSpec, annotations map[string]string) {
|
||||
template.SetAnnotations(annotations)
|
||||
}
|
||||
|
||||
func (d Deployment) setLabels(resource *appsv1.Deployment, labels map[string]string) {
|
||||
resource.SetLabels(labels)
|
||||
}
|
||||
@@ -1064,3 +1093,13 @@ func (d Deployment) setToleration(spec *corev1.PodSpec, tcp kamajiv1alpha1.Tenan
|
||||
func (d Deployment) setAffinity(spec *corev1.PodSpec, tcp kamajiv1alpha1.TenantControlPlane) {
|
||||
spec.Affinity = tcp.Spec.ControlPlane.Deployment.Affinity
|
||||
}
|
||||
|
||||
func (d Deployment) setServiceAccount(spec *corev1.PodSpec, tcp kamajiv1alpha1.TenantControlPlane) {
|
||||
if len(tcp.Spec.ControlPlane.Deployment.ServiceAccountName) > 0 {
|
||||
spec.ServiceAccountName = tcp.Spec.ControlPlane.Deployment.ServiceAccountName
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
spec.ServiceAccountName = "default"
|
||||
}
|
||||
|
||||
@@ -21,18 +21,26 @@ func NewStorageConnection(ctx context.Context, client client.Client, ds kamajiv1
|
||||
|
||||
switch ds.Spec.Driver {
|
||||
case kamajiv1alpha1.KineMySQLDriver:
|
||||
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
|
||||
|
||||
if ds.Spec.TLSConfig != nil {
|
||||
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
|
||||
}
|
||||
|
||||
cc.Parameters = map[string][]string{
|
||||
"multiStatements": {"true"},
|
||||
}
|
||||
|
||||
return NewMySQLConnection(*cc)
|
||||
case kamajiv1alpha1.KinePostgreSQLDriver:
|
||||
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
|
||||
if ds.Spec.TLSConfig != nil {
|
||||
cc.TLSConfig.ServerName = cc.Endpoints[0].Host
|
||||
}
|
||||
|
||||
return NewPostgreSQLConnection(*cc)
|
||||
case kamajiv1alpha1.EtcdDriver:
|
||||
return NewETCDConnection(*cc)
|
||||
case kamajiv1alpha1.KineNatsDriver:
|
||||
return NewNATSConnection(*cc)
|
||||
default:
|
||||
return nil, fmt.Errorf("%s is not a valid driver", ds.Spec.Driver)
|
||||
}
|
||||
|
||||
@@ -36,29 +36,41 @@ type ConnectionConfig struct {
|
||||
}
|
||||
|
||||
func NewConnectionConfig(ctx context.Context, client client.Client, ds kamajiv1alpha1.DataStore) (*ConnectionConfig, error) {
|
||||
ca, err := ds.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var tlsConfig *tls.Config
|
||||
|
||||
if ds.Spec.TLSConfig != nil {
|
||||
ca, err := ds.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rootCAs := x509.NewCertPool()
|
||||
if ok := rootCAs.AppendCertsFromPEM(ca); !ok {
|
||||
return nil, fmt.Errorf("error create root CA for the DB connector")
|
||||
}
|
||||
|
||||
tlsConfig = &tls.Config{
|
||||
RootCAs: rootCAs,
|
||||
}
|
||||
}
|
||||
|
||||
crt, err := ds.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ds.Spec.TLSConfig != nil && ds.Spec.TLSConfig.ClientCertificate != nil {
|
||||
crt, err := ds.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := ds.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, err := ds.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rootCAs := x509.NewCertPool()
|
||||
if ok := rootCAs.AppendCertsFromPEM(ca); !ok {
|
||||
return nil, fmt.Errorf("error create root CA for the DB connector")
|
||||
}
|
||||
certificate, err := tls.X509KeyPair(crt, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot retrieve x.509 key pair from the Kine Secret")
|
||||
}
|
||||
|
||||
certificate, err := tls.X509KeyPair(crt, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot retrieve x.509 key pair from the Kine Secret")
|
||||
tlsConfig.Certificates = []tls.Certificate{certificate}
|
||||
}
|
||||
|
||||
var user, password string
|
||||
@@ -99,10 +111,7 @@ func NewConnectionConfig(ctx context.Context, client client.Client, ds kamajiv1a
|
||||
User: user,
|
||||
Password: password,
|
||||
Endpoints: eps,
|
||||
TLSConfig: &tls.Config{
|
||||
RootCAs: rootCAs,
|
||||
Certificates: []tls.Certificate{certificate},
|
||||
},
|
||||
TLSConfig: tlsConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -112,12 +112,14 @@ func NewMySQLConnection(config ConnectionConfig) (Connection, error) {
|
||||
|
||||
tlsKey := "mysql"
|
||||
|
||||
if err = mysql.RegisterTLSConfig(tlsKey, config.TLSConfig); err != nil {
|
||||
return nil, err
|
||||
if config.TLSConfig != nil {
|
||||
if err = mysql.RegisterTLSConfig(tlsKey, config.TLSConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mysqlConfig.TLSConfig = tlsKey
|
||||
}
|
||||
|
||||
mysqlConfig.DBName = config.DBName
|
||||
mysqlConfig.TLSConfig = tlsKey
|
||||
parsedDSN := mysqlConfig.FormatDSN()
|
||||
|
||||
db, err := sql.Open("mysql", parsedDSN)
|
||||
|
||||
184
internal/datastore/nats.go
Normal file
184
internal/datastore/nats.go
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
// NATSConnection represents a connection to a NATS KV store.
|
||||
type NATSConnection struct {
|
||||
js nats.JetStreamContext
|
||||
conn *nats.Conn
|
||||
config ConnectionConfig
|
||||
}
|
||||
|
||||
// NewNATSConnection initializes a connection to NATS and sets up the KV store.
|
||||
func NewNATSConnection(config ConnectionConfig) (*NATSConnection, error) {
|
||||
var endpoints string
|
||||
|
||||
if len(config.Endpoints) > 1 {
|
||||
// comma separated list of endpoints
|
||||
var ep []string
|
||||
for _, e := range config.Endpoints {
|
||||
ep = append(ep, fmt.Sprintf("nats://%s", e.String()))
|
||||
}
|
||||
|
||||
endpoints = strings.Join(ep, ",")
|
||||
} else {
|
||||
endpoints = fmt.Sprintf("nats://%s", config.Endpoints[0].String())
|
||||
}
|
||||
|
||||
var conn *nats.Conn
|
||||
var err error
|
||||
var natsOpts []nats.Option
|
||||
|
||||
if config.TLSConfig != nil {
|
||||
natsOpts = append(natsOpts, nats.Secure(config.TLSConfig))
|
||||
}
|
||||
|
||||
if config.User != "" && config.Password != "" {
|
||||
natsOpts = append(natsOpts, nats.UserInfo(config.User, config.Password))
|
||||
}
|
||||
|
||||
conn, err = nats.Connect(endpoints, natsOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
js, err := conn.JetStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &NATSConnection{
|
||||
js: js,
|
||||
conn: conn,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) CreateUser(_ context.Context, _, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) CreateDB(_ context.Context, dbName string) error {
|
||||
_, err := nc.js.CreateKeyValue(&nats.KeyValueConfig{Bucket: dbName})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to create the datastore")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) GrantPrivileges(_ context.Context, _, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) UserExists(_ context.Context, _ string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) DBExists(_ context.Context, dbName string) (bool, error) {
|
||||
_, err := nc.js.KeyValue(dbName)
|
||||
if err != nil {
|
||||
if errors.Is(err, nats.ErrBucketNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) GrantPrivilegesExists(_ context.Context, _, _ string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) DeleteUser(_ context.Context, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) DeleteDB(_ context.Context, dbName string) error {
|
||||
err := nc.js.DeleteKeyValue(dbName)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) RevokePrivileges(_ context.Context, _, _ string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) GetConnectionString() string {
|
||||
return nc.config.Endpoints[0].String()
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) Close() error {
|
||||
return nc.conn.Drain()
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) Check(_ context.Context) error {
|
||||
status := nc.conn.Status()
|
||||
|
||||
if status != nats.CONNECTED {
|
||||
return errors.New("connection to NATS is not established")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) Driver() string {
|
||||
return string(kamajiv1alpha1.KineNatsDriver)
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) GetConfig() ConnectionConfig {
|
||||
return nc.config
|
||||
}
|
||||
|
||||
func (nc *NATSConnection) Migrate(ctx context.Context, tcp kamajiv1alpha1.TenantControlPlane, target Connection) error {
|
||||
targetClient := target.(*NATSConnection) //nolint:forcetypeassert
|
||||
dbName := tcp.Status.Storage.Setup.Schema
|
||||
|
||||
targetKv, err := targetClient.js.KeyValue(dbName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sourceKv, err := nc.js.KeyValue(dbName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := target.Check(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy all keys from source to target
|
||||
keys, err := sourceKv.Keys()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
entry, err := sourceKv.Get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = targetKv.Put(key, entry.Value())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-pg/pg/v10"
|
||||
goerrors "github.com/pkg/errors"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/datastore/errors"
|
||||
@@ -34,6 +35,7 @@ const (
|
||||
type PostgreSQLConnection struct {
|
||||
db *pg.DB
|
||||
connection ConnectionEndpoint
|
||||
rootUser string
|
||||
switchDatabaseFn func(dbName string) *pg.DB
|
||||
}
|
||||
|
||||
@@ -114,6 +116,7 @@ func NewPostgreSQLConnection(config ConnectionConfig) (Connection, error) {
|
||||
return &PostgreSQLConnection{
|
||||
db: pg.Connect(opt),
|
||||
switchDatabaseFn: fn,
|
||||
rootUser: config.User,
|
||||
connection: config.Endpoints[0],
|
||||
}, nil
|
||||
}
|
||||
@@ -232,6 +235,10 @@ func (r *PostgreSQLConnection) DeleteUser(ctx context.Context, user string) erro
|
||||
}
|
||||
|
||||
func (r *PostgreSQLConnection) DeleteDB(ctx context.Context, dbName string) error {
|
||||
if err := r.GrantPrivileges(ctx, r.rootUser, dbName); err != nil {
|
||||
return errors.NewCannotDeleteDatabaseError(goerrors.Wrap(err, "cannot grant privileges to root user"))
|
||||
}
|
||||
|
||||
if _, err := r.db.ExecContext(ctx, fmt.Sprintf(postgresqlDropDBStatement, dbName)); err != nil {
|
||||
return errors.NewCannotDeleteDatabaseError(err)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ func (r *Certificate) Define(_ context.Context, tenantControlPlane *kamajiv1alph
|
||||
Name: r.getPrefixedName(tenantControlPlane),
|
||||
Namespace: tenantControlPlane.GetNamespace(),
|
||||
},
|
||||
Data: map[string][]byte{},
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -80,79 +79,93 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al
|
||||
return func() error {
|
||||
logger := log.FromContext(ctx, "resource", r.GetName())
|
||||
|
||||
ca, err := r.DataStore.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, r.Client)
|
||||
if err != nil {
|
||||
logger.Error(err, "cannot retrieve CA certificate content")
|
||||
if r.DataStore.Spec.TLSConfig != nil {
|
||||
ca, err := r.DataStore.Spec.TLSConfig.CertificateAuthority.Certificate.GetContent(ctx, r.Client)
|
||||
if err != nil {
|
||||
logger.Error(err, "cannot retrieve CA certificate content")
|
||||
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
r.resource.Data["ca.crt"] = ca
|
||||
if r.resource.Data == nil {
|
||||
r.resource.Data = map[string][]byte{}
|
||||
}
|
||||
|
||||
r.resource.SetLabels(utilities.MergeMaps(
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "x509",
|
||||
},
|
||||
))
|
||||
r.resource.Data["ca.crt"] = ca
|
||||
|
||||
if err = ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme()); err != nil {
|
||||
logger.Error(err, "cannot set controller reference", "resource", r.GetName())
|
||||
r.resource.SetLabels(utilities.MergeMaps(
|
||||
utilities.KamajiLabels(tenantControlPlane.GetName(), r.GetName()),
|
||||
map[string]string{
|
||||
constants.ControllerLabelResource: "x509",
|
||||
},
|
||||
))
|
||||
|
||||
return err
|
||||
}
|
||||
if err = ctrl.SetControllerReference(tenantControlPlane, r.resource, r.Client.Scheme()); err != nil {
|
||||
logger.Error(err, "cannot set controller reference", "resource", r.GetName())
|
||||
|
||||
if utilities.GetObjectChecksum(r.resource) == utilities.CalculateMapChecksum(r.resource.Data) {
|
||||
if r.DataStore.Spec.Driver == kamajiv1alpha1.EtcdDriver {
|
||||
if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"]); isValid {
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
if utilities.GetObjectChecksum(r.resource) == utilities.CalculateMapChecksum(r.resource.Data) {
|
||||
if r.DataStore.Spec.Driver == kamajiv1alpha1.EtcdDriver {
|
||||
if isValid, _ := crypto.IsValidCertificateKeyPairBytes(r.resource.Data["server.crt"], r.resource.Data["server.key"]); isValid {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var crt, key *bytes.Buffer
|
||||
|
||||
switch r.DataStore.Spec.Driver {
|
||||
case kamajiv1alpha1.EtcdDriver:
|
||||
var privateKey []byte
|
||||
// When dealing with the etcd storage we cannot use the basic authentication, thus the generation of a
|
||||
// certificate used for authentication is mandatory, along with the CA private key.
|
||||
if privateKey, err = r.DataStore.Spec.TLSConfig.CertificateAuthority.PrivateKey.GetContent(ctx, r.Client); err != nil {
|
||||
logger.Error(err, "unable to retrieve CA private key content")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if crt, key, err = crypto.GenerateCertificatePrivateKeyPair(crypto.NewCertificateTemplate(tenantControlPlane.Status.Storage.Setup.User), ca, privateKey); err != nil {
|
||||
logger.Error(err, "unable to generate certificate and private key")
|
||||
|
||||
return err
|
||||
}
|
||||
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver, kamajiv1alpha1.KineNatsDriver:
|
||||
var crtBytes, keyBytes []byte
|
||||
// For the SQL drivers we just need to copy the certificate, since the basic authentication is used
|
||||
// to connect to the desired schema and database.
|
||||
|
||||
if r.DataStore.Spec.TLSConfig.ClientCertificate != nil {
|
||||
if crtBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, r.Client); err != nil {
|
||||
logger.Error(err, "unable to retrieve certificate content")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
crt = bytes.NewBuffer(crtBytes)
|
||||
|
||||
if keyBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, r.Client); err != nil {
|
||||
logger.Error(err, "unable to retrieve private key content")
|
||||
|
||||
return err
|
||||
}
|
||||
key = bytes.NewBuffer(keyBytes)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unrecognized driver for Certificate generation")
|
||||
}
|
||||
|
||||
if r.DataStore.Spec.TLSConfig.ClientCertificate != nil {
|
||||
r.resource.Data["server.crt"] = crt.Bytes()
|
||||
r.resource.Data["server.key"] = key.Bytes()
|
||||
}
|
||||
} else {
|
||||
// set r.resource.Data to empty to allow switching from TLS to non-tls
|
||||
r.resource.Data = map[string][]byte{}
|
||||
}
|
||||
|
||||
var crt, key *bytes.Buffer
|
||||
|
||||
switch r.DataStore.Spec.Driver {
|
||||
case kamajiv1alpha1.EtcdDriver:
|
||||
var privateKey []byte
|
||||
// When dealing with the etcd storage we cannot use the basic authentication, thus the generation of a
|
||||
// certificate used for authentication is mandatory, along with the CA private key.
|
||||
if privateKey, err = r.DataStore.Spec.TLSConfig.CertificateAuthority.PrivateKey.GetContent(ctx, r.Client); err != nil {
|
||||
logger.Error(err, "unable to retrieve CA private key content")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if crt, key, err = crypto.GenerateCertificatePrivateKeyPair(crypto.NewCertificateTemplate(tenantControlPlane.Status.Storage.Setup.User), ca, privateKey); err != nil {
|
||||
logger.Error(err, "unable to generate certificate and private key")
|
||||
|
||||
return err
|
||||
}
|
||||
case kamajiv1alpha1.KineMySQLDriver, kamajiv1alpha1.KinePostgreSQLDriver:
|
||||
var crtBytes, keyBytes []byte
|
||||
// For the SQL drivers we just need to copy the certificate, since the basic authentication is used
|
||||
// to connect to the desired schema and database.
|
||||
if crtBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.Certificate.GetContent(ctx, r.Client); err != nil {
|
||||
logger.Error(err, "unable to retrieve certificate content")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
crt = bytes.NewBuffer(crtBytes)
|
||||
|
||||
if keyBytes, err = r.DataStore.Spec.TLSConfig.ClientCertificate.PrivateKey.GetContent(ctx, r.Client); err != nil {
|
||||
logger.Error(err, "unable to retrieve private key content")
|
||||
|
||||
return err
|
||||
}
|
||||
key = bytes.NewBuffer(keyBytes)
|
||||
default:
|
||||
return fmt.Errorf("unrecognized driver for Certificate generation")
|
||||
}
|
||||
|
||||
r.resource.Data["server.crt"] = crt.Bytes()
|
||||
r.resource.Data["server.key"] = key.Bytes()
|
||||
|
||||
utilities.SetObjectChecksum(r.resource, r.resource.Data)
|
||||
|
||||
return nil
|
||||
|
||||
62
internal/resources/datastore/datastore_multitenancy.go
Normal file
62
internal/resources/datastore/datastore_multitenancy.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
)
|
||||
|
||||
type MultiTenancy struct {
|
||||
DataStore kamajiv1alpha1.DataStore
|
||||
}
|
||||
|
||||
func (m MultiTenancy) Define(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m MultiTenancy) ShouldCleanup(*kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m MultiTenancy) CleanUp(context.Context, *kamajiv1alpha1.TenantControlPlane) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (m MultiTenancy) CreateOrUpdate(_ context.Context, tcp *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
|
||||
// If the NATS Datastore is already used by a Tenant Control Plane
|
||||
// and a new one is reclaiming it, we need to stop it, since it's not allowed.
|
||||
// TODO(prometherion): remove this after multi-tenancy is implemented for NATS.
|
||||
if m.DataStore.Spec.Driver != kamajiv1alpha1.KineNatsDriver {
|
||||
return controllerutil.OperationResultNone, nil
|
||||
}
|
||||
|
||||
usedBy := sets.New[string](m.DataStore.Status.UsedBy...)
|
||||
|
||||
switch {
|
||||
case usedBy.Has(tcp.Namespace + "/" + tcp.Name):
|
||||
return controllerutil.OperationResultNone, nil
|
||||
case usedBy.Len() == 0:
|
||||
return controllerutil.OperationResultNone, nil
|
||||
default:
|
||||
return controllerutil.OperationResultNone, errors.New("NATS doesn't support multi-tenancy, the current datastore is already in use")
|
||||
}
|
||||
}
|
||||
|
||||
func (m MultiTenancy) GetName() string {
|
||||
return "ds.multitenancy"
|
||||
}
|
||||
|
||||
func (m MultiTenancy) ShouldStatusBeUpdated(context.Context, *kamajiv1alpha1.TenantControlPlane) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m MultiTenancy) UpdateTenantControlPlaneStatus(context.Context, *kamajiv1alpha1.TenantControlPlane) error {
|
||||
return nil
|
||||
}
|
||||
@@ -104,9 +104,10 @@ func (r *Config) UpdateTenantControlPlaneStatus(_ context.Context, tenantControl
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Config) mutate(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {
|
||||
func (r *Config) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) controllerutil.MutateFn {
|
||||
return func() error {
|
||||
var password []byte
|
||||
var username []byte
|
||||
|
||||
hash := utilities.GetObjectChecksum(r.resource)
|
||||
switch {
|
||||
@@ -133,10 +134,31 @@ func (r *Config) mutate(_ context.Context, tenantControlPlane *kamajiv1alpha1.Te
|
||||
finalizersList.Insert(finalizers.DatastoreSecretFinalizer)
|
||||
r.resource.SetFinalizers(finalizersList.UnsortedList())
|
||||
|
||||
// TODO(thecodeassassin): remove this after multi-tenancy is implemented for NATS.
|
||||
// Due to NATS is missing a programmatic approach to create users and password,
|
||||
// we're using the Datastore root password.
|
||||
if r.DataStore.Spec.Driver == kamajiv1alpha1.KineNatsDriver {
|
||||
// set username and password to the basicAuth values of the NATS datastore
|
||||
u, err := r.DataStore.Spec.BasicAuth.Username.GetContent(ctx, r.Client)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to retrieve the username for the NATS datastore")
|
||||
}
|
||||
|
||||
p, err := r.DataStore.Spec.BasicAuth.Password.GetContent(ctx, r.Client)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to retrieve the password for the NATS datastore")
|
||||
}
|
||||
|
||||
username = u
|
||||
password = p
|
||||
} else {
|
||||
username = coalesceFn(tenantControlPlane.Status.Storage.Setup.User)
|
||||
}
|
||||
|
||||
r.resource.Data = map[string][]byte{
|
||||
"DB_CONNECTION_STRING": []byte(r.ConnString),
|
||||
"DB_SCHEMA": coalesceFn(tenantControlPlane.Status.Storage.Setup.Schema),
|
||||
"DB_USER": coalesceFn(tenantControlPlane.Status.Storage.Setup.User),
|
||||
"DB_USER": username,
|
||||
"DB_PASSWORD": password,
|
||||
}
|
||||
|
||||
|
||||
@@ -126,12 +126,7 @@ func (r *Agent) mutate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.T
|
||||
))
|
||||
|
||||
r.resource.Spec.Template.Spec.PriorityClassName = "system-cluster-critical"
|
||||
r.resource.Spec.Template.Spec.Tolerations = []corev1.Toleration{
|
||||
{
|
||||
Key: "CriticalAddonsOnly",
|
||||
Operator: "Exists",
|
||||
},
|
||||
}
|
||||
r.resource.Spec.Template.Spec.Tolerations = tenantControlPlane.Spec.Addons.Konnectivity.KonnectivityAgentSpec.Tolerations
|
||||
r.resource.Spec.Template.Spec.NodeSelector = map[string]string{
|
||||
"kubernetes.io/os": "linux",
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func (k *KubernetesUpgrade) CreateOrUpdate(ctx context.Context, tenantControlPla
|
||||
return controllerutil.OperationResultNone, errors.Wrap(err, "cannot create REST client required for Kubernetes upgrade plan")
|
||||
}
|
||||
|
||||
versionGetter := kamajiupgrade.NewKamajiKubeVersionGetter(clientSet)
|
||||
versionGetter := kamajiupgrade.NewKamajiKubeVersionGetter(clientSet, tenantControlPlane.Status.Kubernetes.Version.Version)
|
||||
|
||||
if _, err = upgrade.GetAvailableUpgrades(versionGetter, false, false, clientSet, &printers.Discard{}); err != nil {
|
||||
return controllerutil.OperationResultNone, errors.Wrap(err, "cannot retrieve available Upgrades for Kubernetes upgrade plan")
|
||||
|
||||
@@ -16,12 +16,13 @@ import (
|
||||
|
||||
type kamajiKubeVersionGetter struct {
|
||||
upgrade.VersionGetter
|
||||
Version string
|
||||
}
|
||||
|
||||
func NewKamajiKubeVersionGetter(restClient kubernetes.Interface) upgrade.VersionGetter {
|
||||
func NewKamajiKubeVersionGetter(restClient kubernetes.Interface, version string) upgrade.VersionGetter {
|
||||
kubeVersionGetter := upgrade.NewOfflineVersionGetter(upgrade.NewKubeVersionGetter(restClient), KubeadmVersion)
|
||||
|
||||
return &kamajiKubeVersionGetter{VersionGetter: kubeVersionGetter}
|
||||
return &kamajiKubeVersionGetter{VersionGetter: kubeVersionGetter, Version: version}
|
||||
}
|
||||
|
||||
func (k kamajiKubeVersionGetter) ClusterVersion() (string, *versionutil.Version, error) {
|
||||
@@ -51,3 +52,9 @@ func (k kamajiKubeVersionGetter) VersionFromCILabel(ciVersionLabel, description
|
||||
func (k kamajiKubeVersionGetter) KubeletVersions() (map[string][]string, error) {
|
||||
return k.VersionGetter.KubeletVersions()
|
||||
}
|
||||
|
||||
func (k kamajiKubeVersionGetter) ComponentVersions(string) (map[string][]string, error) {
|
||||
return map[string][]string{
|
||||
k.Version: {"kamaji"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
package upgrade
|
||||
|
||||
const (
|
||||
KubeadmVersion = "v1.30.0"
|
||||
KubeadmVersion = "v1.30.2"
|
||||
)
|
||||
|
||||
@@ -14,13 +14,7 @@ func ArgsFromSliceToMap(args []string) (m map[string]string) {
|
||||
m = make(map[string]string)
|
||||
|
||||
for _, arg := range args {
|
||||
parts := strings.SplitN(arg, "=", 2)
|
||||
|
||||
flag, value := parts[0], ""
|
||||
|
||||
if len(parts) > 1 {
|
||||
value = parts[1]
|
||||
}
|
||||
flag, value, _ := strings.Cut(arg, "=")
|
||||
|
||||
m[flag] = value
|
||||
}
|
||||
|
||||
30
internal/utilities/args_test.go
Normal file
30
internal/utilities/args_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package utilities
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestArgsFromSliceToMap(t *testing.T) {
|
||||
tests := map[string]map[string]string{
|
||||
"--a": {"--a": ""},
|
||||
"--a=": {"--a": ""},
|
||||
"--a=b": {"--a": "b"},
|
||||
"--a=b=c": {"--a": "b=c"},
|
||||
}
|
||||
|
||||
got := ArgsFromSliceToMap([]string{})
|
||||
if len(got) != 0 {
|
||||
t.Errorf("expected empty input to result in empty map, but got %+v", got)
|
||||
}
|
||||
|
||||
for arg, expect := range tests {
|
||||
got := ArgsFromSliceToMap([]string{arg})
|
||||
if !maps.Equal(expect, got) {
|
||||
t.Errorf("expected input %q to result in %+v, but got %+v", arg, expect, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func GetRESTClientConfig(ctx context.Context, client client.Client, tenantContro
|
||||
}
|
||||
|
||||
config := &restclient.Config{
|
||||
Host: fmt.Sprintf("https://%s.%s.svc.cluster.local:%d", tenantControlPlane.GetName(), tenantControlPlane.GetNamespace(), tenantControlPlane.Spec.NetworkProfile.Port),
|
||||
Host: fmt.Sprintf("https://%s.%s.svc:%d", tenantControlPlane.GetName(), tenantControlPlane.GetNamespace(), tenantControlPlane.Spec.NetworkProfile.Port),
|
||||
TLSClientConfig: restclient.TLSClientConfig{
|
||||
CAData: kubeconfig.Clusters[0].Cluster.CertificateAuthorityData,
|
||||
CertData: kubeconfig.AuthInfos[0].AuthInfo.ClientCertificateData,
|
||||
|
||||
@@ -84,6 +84,10 @@ func (d DataStoreValidation) validateBasicAuth(ctx context.Context, ds kamajiv1a
|
||||
}
|
||||
|
||||
func (d DataStoreValidation) validateTLSConfig(ctx context.Context, ds kamajiv1alpha1.DataStore) error {
|
||||
if ds.Spec.TLSConfig == nil && ds.Spec.Driver != kamajiv1alpha1.EtcdDriver {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := d.validateContentReference(ctx, ds.Spec.TLSConfig.CertificateAuthority.Certificate); err != nil {
|
||||
return fmt.Errorf("CA certificate is not valid, %w", err)
|
||||
}
|
||||
|
||||
71
internal/webhook/handlers/tcp_service_cidr.go
Normal file
71
internal/webhook/handlers/tcp_service_cidr.go
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 Clastix Labs
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"gomodules.xyz/jsonpatch/v2"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
|
||||
"github.com/clastix/kamaji/internal/webhook/utils"
|
||||
)
|
||||
|
||||
type TenantControlPlaneServiceCIDR struct{}
|
||||
|
||||
func (t TenantControlPlaneServiceCIDR) handle(tcp *kamajiv1alpha1.TenantControlPlane) error {
|
||||
if tcp.Spec.Addons.CoreDNS == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, cidr, err := net.ParseCIDR(tcp.Spec.NetworkProfile.ServiceCIDR)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse Service CIDR, %s", err.Error())
|
||||
}
|
||||
|
||||
for _, serviceIP := range tcp.Spec.NetworkProfile.DNSServiceIPs {
|
||||
ip := net.ParseIP(serviceIP)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("unable to parse IP address %s", serviceIP)
|
||||
}
|
||||
|
||||
if !cidr.Contains(ip) {
|
||||
return fmt.Errorf("the Service CIDR does not contain the DNS Service IP %s", serviceIP)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneServiceCIDR) OnCreate(object runtime.Object) AdmissionResponse {
|
||||
return func(context.Context, admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
if err := t.handle(tcp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneServiceCIDR) OnDelete(runtime.Object) AdmissionResponse {
|
||||
return utils.NilOp()
|
||||
}
|
||||
|
||||
func (t TenantControlPlaneServiceCIDR) OnUpdate(object runtime.Object, _ runtime.Object) AdmissionResponse {
|
||||
return func(ctx context.Context, req admission.Request) ([]jsonpatch.JsonPatchOperation, error) {
|
||||
tcp := object.(*kamajiv1alpha1.TenantControlPlane) //nolint:forcetypeassert
|
||||
|
||||
if err := t.handle(tcp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
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