Skip to content

Commit

Permalink
feat!: monitoring multiple clusters
Browse files Browse the repository at this point in the history
Signed-off-by: Dario Tranchitella <dario@tranchitella.eu>
  • Loading branch information
prometherion committed Nov 20, 2023
1 parent 7fedf7c commit 3af4434
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 30 deletions.
9 changes: 6 additions & 3 deletions api/v1alpha1/k8sgpt_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,12 @@ type K8sGPTSpec struct {
Filters []string `json:"filters,omitempty"`
ExtraOptions *ExtraOptionsRef `json:"extraOptions,omitempty"`
Sink *WebhookRef `json:"sink,omitempty"`
AI *AISpec `json:"ai,omitempty"`
RemoteCache *RemoteCacheRef `json:"remoteCache,omitempty"`
Integrations *Integrations `json:"integrations,omitempty"`
// Define the kubeconfig the Deployment must use.
// If empty, the Deployment will use the ServiceAccount provided by Kubernetes itself.
Kubeconfig *SecretRef `json:"kubeconfig,omitempty"`
AI *AISpec `json:"ai,omitempty"`
RemoteCache *RemoteCacheRef `json:"remoteCache,omitempty"`
Integrations *Integrations `json:"integrations,omitempty"`
}

const (
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions config/crd/bases/core.k8sgpt.ai_k8sgpts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ spec:
type: boolean
type: object
type: object
kubeconfig:
description: Define the kubeconfig the Deployment must use. If empty,
the Deployment will use the ServiceAccount provided by Kubernetes
itself.
properties:
key:
type: string
name:
type: string
type: object
noCache:
type: boolean
remoteCache:
Expand Down
2 changes: 1 addition & 1 deletion controllers/k8sgpt_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
// Check and see if the instance is new or has a K8sGPT deployment in flight
deployment := v1.Deployment{}
err = r.Get(ctx, client.ObjectKey{Namespace: k8sgptConfig.Namespace,
Name: "k8sgpt-deployment"}, &deployment)
Name: k8sgptConfig.Name}, &deployment)
if client.IgnoreNotFound(err) != nil {
k8sgptReconcileErrorCount.Inc()
return r.finishReconcile(err, false)
Expand Down
2 changes: 1 addition & 1 deletion pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func GenerateAddress(ctx context.Context, cli client.Client, k8sgptConfig *v1alp
// Get service IP and port for k8sgpt-deployment
svc := &corev1.Service{}
err := cli.Get(ctx, client.ObjectKey{Namespace: k8sgptConfig.Namespace,
Name: "k8sgpt"}, svc)
Name: k8sgptConfig.Name}, svc)
if err != nil {
return "", nil
}
Expand Down
84 changes: 59 additions & 25 deletions pkg/resources/k8sgpt.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package resources
import (
"context"
err "errors"
"fmt"

"github.com/k8sgpt-ai/k8sgpt-operator/api/v1alpha1"
"github.com/k8sgpt-ai/k8sgpt-operator/pkg/utils"
Expand All @@ -29,6 +30,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
Expand All @@ -39,15 +41,14 @@ type SyncOrDestroy int
const (
SyncOp SyncOrDestroy = iota
DestroyOp
DeploymentName = "k8sgpt-deployment"
)

// GetService Create service for K8sGPT
func GetService(config v1alpha1.K8sGPT) (*corev1.Service, error) {
// Create service
service := corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "k8sgpt",
Name: config.Name,
Namespace: config.Namespace,
OwnerReferences: []metav1.OwnerReference{
{
Expand All @@ -62,7 +63,7 @@ func GetService(config v1alpha1.K8sGPT) (*corev1.Service, error) {
},
Spec: corev1.ServiceSpec{
Selector: map[string]string{
"app": DeploymentName,
"app": config.Name,
},
Ports: []corev1.ServicePort{
{
Expand Down Expand Up @@ -171,13 +172,13 @@ func GetClusterRole(config v1alpha1.K8sGPT) (*r1.ClusterRole, error) {
}

// GetDeployment Create deployment with the latest K8sGPT image
func GetDeployment(config v1alpha1.K8sGPT) (*appsv1.Deployment, error) {
func GetDeployment(config v1alpha1.K8sGPT, outOfClusterMode bool) (*appsv1.Deployment, error) {

// Create deployment
replicas := int32(1)
deployment := appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: DeploymentName,
Name: config.Name,
Namespace: config.Namespace,
OwnerReferences: []metav1.OwnerReference{
{
Expand All @@ -194,13 +195,13 @@ func GetDeployment(config v1alpha1.K8sGPT) (*appsv1.Deployment, error) {
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": DeploymentName,
"app": config.Name,
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": DeploymentName,
"app": config.Name,
},
},
Spec: corev1.PodSpec{
Expand Down Expand Up @@ -264,6 +265,35 @@ func GetDeployment(config v1alpha1.K8sGPT) (*appsv1.Deployment, error) {
},
},
}
if outOfClusterMode {
// No need of ServiceAccount since the Deployment will use
// a kubeconfig pointing to an external cluster.
deployment.Spec.Template.Spec.ServiceAccountName = ""
deployment.Spec.Template.Spec.AutomountServiceAccountToken = ptr.To(false)

kubeconfigPath := fmt.Sprintf("/tmp/%s", config.Name)

deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, fmt.Sprintf("--kubeconfig=%s/kubeconfig", kubeconfigPath))
deployment.Spec.Template.Spec.Containers[0].VolumeMounts = append(deployment.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
Name: "kubeconfig",
ReadOnly: true,
MountPath: kubeconfigPath,
})
deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes, corev1.Volume{
Name: "kubeconfig",
VolumeSource: v1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: config.Spec.Kubeconfig.Name,
Items: []corev1.KeyToPath{
{
Key: config.Spec.Kubeconfig.Key,
Path: "kubeconfig",
},
},
},
},
})
}
if config.Spec.AI.Secret != nil {
password := corev1.EnvVar{
Name: "K8SGPT_PASSWORD",
Expand Down Expand Up @@ -338,35 +368,39 @@ func Sync(ctx context.Context, c client.Client,

var objs []client.Object

svc, er := GetService(config)
if er != nil {
return er
}
outOfClusterMode := config.Spec.Kubeconfig != nil

objs = append(objs, svc)
if !outOfClusterMode {
svcAcc, er := GetServiceAccount(config)
if er != nil {
return er
}

svcAcc, er := GetServiceAccount(config)
if er != nil {
return er
}
objs = append(objs, svcAcc)

objs = append(objs, svcAcc)
clusterRole, er := GetClusterRole(config)
if er != nil {
return er
}

clusterRole, er := GetClusterRole(config)
if er != nil {
return er
}
objs = append(objs, clusterRole)

clusterRoleBinding, er := GetClusterRoleBinding(config)
if er != nil {
return er
}

objs = append(objs, clusterRole)
objs = append(objs, clusterRoleBinding)
}

clusterRoleBinding, er := GetClusterRoleBinding(config)
svc, er := GetService(config)
if er != nil {
return er
}

objs = append(objs, clusterRoleBinding)
objs = append(objs, svc)

deployment, er := GetDeployment(config)
deployment, er := GetDeployment(config, outOfClusterMode)
if er != nil {
return er
}
Expand Down

0 comments on commit 3af4434

Please sign in to comment.