Compare commits

...

19 Commits

Author SHA1 Message Date
Dario Tranchitella
f4c0cec4f9 chore(helm): releasing v1.0.0 2024-06-28 10:50:18 +02:00
Dario Tranchitella
db3a092d3d chore(kustomize): releasing v1.0.0 2024-06-28 10:50:18 +02:00
bsctl
d590b9d17d feat(docs): conformance for v1.30
Signed-off-by: bsctl <adriano@clastix.io>
2024-06-27 16:26:57 +02:00
bsctl
9147ae9977 feat(docs): conformance for v1.29
Signed-off-by: bsctl <adriano@clastix.io>
2024-06-27 16:26:57 +02:00
Dario Tranchitella
d2ff044228 chore(kustomize): enable telemetry
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
bsctl
a147869944 feat(helm): enable telemetry
Signed-off-by: bsctl <adriano@clastix.io>
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
bsctl
056ad4002a feat(docs): document telemetry
Signed-off-by: bsctl <adriano@clastix.io>
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
Dario Tranchitella
91cbf0c507 feat: telemetry
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
Dario Tranchitella
d57d5b5a56 feat(deps): bumping up sigs.k8s.io/controller-runtime to v0.18.4
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
Dario Tranchitella
24714d7168 chore(lease): changing lease holder name
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-27 11:38:41 +02:00
devopsdatacomm
422d225682 chore(adopters): adding DCloud as vendor 2024-06-27 06:52:37 +02:00
Dario Tranchitella
c57c07693f chore(helm): releasing v0.6.1
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-24 18:32:02 +02:00
Dario Tranchitella
fa560446f1 chore(kustomize): releasing v0.6.1
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-24 18:32:02 +02:00
Dario Tranchitella
6ba4b4abac feat: supporting k8s v1.30.2
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-06-24 18:32:02 +02:00
Dario Tranchitella
45d0869b91 feat(webhook): validating DNS service IPs on Service CIDR
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-31 12:05:09 +02:00
Dario Tranchitella
511a08889e fix: nil pointer in datastore certificate handler
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
2024-05-31 12:04:28 +02:00
Mario Valderrama
6217f2ca25 feat: add category to CRD 2024-05-24 18:01:27 +02:00
Andrei Kvapil
e51df96777 fix: removing hardcoded cluster.local domain from TCP client
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
2024-05-21 22:25:00 +02:00
Dario Tranchitella
f235689bf5 chore(helm): releasing v0.16.0 chart 2024-05-19 12:09:12 +02:00
35 changed files with 617 additions and 100 deletions

View File

@@ -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

View File

@@ -7,6 +7,7 @@ Feel free to open a Pull-Request to get yours listed.
| Type | Name | Since | Website | Use-Case |
|:-|:-|:-|:-|:-|
| Vendor | DCloud | 2024 | [link](https://dcloud.co.id) | DCloud is an Indonesian Cloud Provider using Kamaji to build and offer [Managed Kubernetes Service](https://dcloud.co.id/dkubes.html). |
| End-user | Sicuro Tech Lab | 2024 | [link](https://sicurotechlab.it/) | Sicuro Tech Lab offers cloud infrastructure for Web Agencies and uses kamaji to provide managed k8s services. |
| R&D | TIM | 2024 | [link](https://www.gruppotim.it) | TIM is an Italian telecommunications company using Kamaji for experimental research and development purposes. |
| End-user | KINX | 2024 | [link](https://kinx.net/?lang=en) | KINX is an Internet infrastructure service provider and will use kamaji for its new [Managed Kubernetes Service](https://kinx.net/service/cloud/kubernetes/intro/?lang=en). |

View File

@@ -3,7 +3,7 @@
# To re-generate a bundle for another specific version without changing the standard setup, you can:
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 0.6.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")
@@ -307,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

View File

@@ -266,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)"

View File

@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: v0.6.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.3
version: 1.0.0
annotations:
catalog.cattle.io/certified: partner
catalog.cattle.io/release-name: kamaji

View File

@@ -1,6 +1,6 @@
# kamaji
![Version: 0.15.3](https://img.shields.io/badge/Version-0.15.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.6.0](https://img.shields.io/badge/AppVersion-v0.6.0-informational?style=flat-square)
![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v1.0.0](https://img.shields.io/badge/AppVersion-v1.0.0-informational?style=flat-square)
Kamaji is the Hosted Control Plane Manager for Kubernetes.
@@ -134,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 |

View File

@@ -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 }}

View File

@@ -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:

View File

@@ -219,4 +219,9 @@ datastore:
cfssl:
image:
repository: cfssl/cfssl
tag: latest
tag: latest
# -- Disable the analytics traces collection
telemetry:
disabled: false

View File

@@ -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")
@@ -194,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()},
@@ -264,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
View 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
}

View File

@@ -8,6 +8,8 @@ metadata:
spec:
group: kamaji.clastix.io
names:
categories:
- kamaji
kind: TenantControlPlane
listKind: TenantControlPlaneList
plural: tenantcontrolplanes

View File

@@ -309,6 +309,8 @@ spec:
- v1
group: kamaji.clastix.io
names:
categories:
- kamaji
kind: TenantControlPlane
listKind: TenantControlPlaneList
plural: tenantcontrolplanes
@@ -8014,7 +8016,7 @@ spec:
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
image: clastix/kamaji:v0.6.0
image: clastix/kamaji:v1.0.0
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -8206,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:

View File

@@ -13,4 +13,4 @@ kind: Kustomization
images:
- name: controller
newName: clastix/kamaji
newTag: v0.6.0
newTag: v1.0.0

View File

@@ -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:

View File

@@ -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)
},

View File

@@ -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{}).

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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{}).

View File

@@ -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)
}

View File

@@ -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

View 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)
}

View File

@@ -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"]

View File

@@ -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" />

49
docs/content/telemetry.md Normal file
View 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.

View File

@@ -76,4 +76,5 @@ nav:
- reference/conformance.md
- reference/versioning.md
- reference/api.md
- 'Telemetry': telemetry.md
- 'Contribute': contribute.md

75
go.mod
View File

@@ -7,18 +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
@@ -26,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.1
k8s.io/apimachinery v0.30.1
k8s.io/apiserver v0.30.1
k8s.io/client-go v0.30.1
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.1
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 (
@@ -152,7 +153,7 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.30.1 // indirect
k8s.io/cli-runtime v0.30.1 // indirect
k8s.io/component-base 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
@@ -166,33 +167,33 @@ require (
)
replace (
k8s.io/api => k8s.io/api v0.30.1
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.30.1
k8s.io/apimachinery => k8s.io/apimachinery v0.30.1
k8s.io/apiserver => k8s.io/apiserver v0.30.1
k8s.io/cli-runtime => k8s.io/cli-runtime v0.30.1
k8s.io/client-go => k8s.io/client-go v0.30.1
k8s.io/cloud-provider => k8s.io/cloud-provider v0.30.1
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.30.1
k8s.io/code-generator => k8s.io/code-generator v0.30.1
k8s.io/component-base => k8s.io/component-base v0.30.1
k8s.io/component-helpers => k8s.io/component-helpers v0.30.1
k8s.io/controller-manager => k8s.io/controller-manager v0.30.1
k8s.io/cri-api => k8s.io/cri-api v0.30.1
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.30.1
k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.30.1
k8s.io/endpointslice => k8s.io/endpointslice v0.30.1
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.30.1
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.30.1
k8s.io/kube-proxy => k8s.io/kube-proxy v0.30.1
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.30.1
k8s.io/kubectl => k8s.io/kubectl v0.30.1
k8s.io/kubelet => k8s.io/kubelet v0.30.1
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.30.1
k8s.io/metrics => k8s.io/metrics v0.30.1
k8s.io/mount-utils => k8s.io/mount-utils v0.30.1
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.30.1
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.30.1
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

71
go.sum
View File

@@ -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=
@@ -1692,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=
@@ -2751,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.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/apiserver v0.30.1 h1:BEWEe8bzS12nMtDKXzCF5Q5ovp6LjjYkSp8qOPk8LZ8=
k8s.io/apiserver v0.30.1/go.mod h1:i87ZnQ+/PGAmSbD/iEKM68bm1D5reX8fO4Ito4B01mo=
k8s.io/cli-runtime v0.30.1 h1:kSBBpfrJGS6lllc24KeniI9JN7ckOOJKnmFYH1RpTOw=
k8s.io/cli-runtime v0.30.1/go.mod h1:zhHgbqI4J00pxb6gM3gJPVf2ysDjhQmQtnTxnMScab8=
k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
k8s.io/cluster-bootstrap v0.30.1 h1:WHh04Oh0YAWMsJ5TXXEF+LGu3g/2ymQOYsH8IopUHlQ=
k8s.io/cluster-bootstrap v0.30.1/go.mod h1:GcLD4Z4GFY+CsNYcaqlSAmxFIHgSMGZHNT4SjA0A6ao=
k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ=
k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI=
k8s.io/component-helpers v0.30.1 h1:/UcxSLzZ0owluTE2WMDrFfZl2L+WVXKdYYYm68qnH7U=
k8s.io/component-helpers v0.30.1/go.mod h1:b1Xk27UJ3p/AmPqDx7khrnSxrdwQy9gTP7O1y6MZ6rg=
k8s.io/cri-api v0.30.1/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=
@@ -2777,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.1/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.1 h1:lDE510UHimfyRfh/c4Erlgg9OEDmHnZce3KKERV1JtI=
k8s.io/kube-proxy v0.30.1/go.mod h1:5aRCUPUowbrps6o8oTJ0oRNVLIvcZvnesGZFFMEWZ08=
k8s.io/kubelet v0.30.1 h1:6gS1gWjrefUGfC/9n0ITOzxnKyt89FfkIhom70Bola4=
k8s.io/kubelet v0.30.1/go.mod h1:5IUeAt3YlIfLNdT/YfRuCCONfEefm7qfcqz81b002Z8=
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.1 h1:XlqS6KslLEA5mQzLK2AJrhr4Z1m8oJfkhHiWJ5lue+I=
k8s.io/kubernetes v1.30.1/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=
@@ -2851,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=

View File

@@ -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
@@ -88,6 +87,10 @@ func (r *Certificate) mutate(ctx context.Context, tenantControlPlane *kamajiv1al
return err
}
if r.resource.Data == nil {
r.resource.Data = map[string][]byte{}
}
r.resource.Data["ca.crt"] = ca
r.resource.SetLabels(utilities.MergeMaps(

View File

@@ -4,5 +4,5 @@
package upgrade
const (
KubeadmVersion = "v1.30.1"
KubeadmVersion = "v1.30.2"
)

View File

@@ -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,

View 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
}
}

View 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)
}

View 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{}
}