diff --git a/controllers/k8sgpt_controller.go b/controllers/k8sgpt_controller.go index ae1eef2e..a34b74f3 100644 --- a/controllers/k8sgpt_controller.go +++ b/controllers/k8sgpt_controller.go @@ -22,6 +22,7 @@ import ( corev1alpha1 "github.com/k8sgpt-ai/k8sgpt-operator/api/v1alpha1" + "github.com/go-logr/logr" "github.com/prometheus/client_golang/prometheus" v1 "k8s.io/api/apps/v1" kcorev1 "k8s.io/api/core/v1" @@ -95,7 +96,8 @@ type K8sGPTReconciler struct { // +kubebuilder:rbac:groups="*",resources="*",verbs="*" // +kubebuilder:rbac:groups="apiextensions.k8s.io",resources="*",verbs="*" func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) + log := log.FromContext(ctx) + log.Info("Reconciling K8sGPT") // Look up the instance for this reconcile request k8sgptConfig := &corev1alpha1.K8sGPT{} @@ -108,7 +110,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr return ctrl.Result{}, client.IgnoreNotFound(err) } - // Add a finaliser if there isn't one + // Add a finalizer if there isn't one if k8sgptConfig.ObjectMeta.DeletionTimestamp.IsZero() { // The object is not being deleted, so if it does not have our finalizer, // then lets add the finalizer and update the object. This is equivalent @@ -119,7 +121,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } } } else { @@ -132,18 +134,18 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } controllerutil.RemoveFinalizer(k8sgptConfig, FinalizerName) if err := r.Update(ctx, k8sgptConfig); err != nil { k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } } // Stop reconciliation as the item is being deleted - return r.finishReconcile(nil, false) + return r.finishReconcile(log, nil, false) } if k8sgptConfig.Spec.AI.BackOff == nil { @@ -155,7 +157,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } } @@ -167,14 +169,14 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } err = resources.Sync(ctx, r.Client, *k8sgptConfig, resources.SyncOp) if err != nil { k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } if deployment.Status.ReadyReplicas > 0 { @@ -196,10 +198,10 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } - return r.finishReconcile(nil, false) + return r.finishReconcile(log, nil, false) } // If the deployment is active, we will query it directly for sis data @@ -208,17 +210,18 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } + // Log address - fmt.Printf("K8sGPT address: %s\n", address) + log.Info(fmt.Sprintf("K8sGPT address: %s", address)) k8sgptClient, err := kclient.NewClient(address) if err != nil { k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } defer k8sgptClient.Close() @@ -230,16 +233,16 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } } if k8sgptConfig.Spec.Integrations != nil { - err = k8sgptClient.AddIntegration(k8sgptConfig) + err = k8sgptClient.AddIntegration(log, k8sgptConfig) if err != nil { k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } } @@ -256,7 +259,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr if k8sgptConfig.Spec.AI.BackOff.Enabled { if analysisRetryCount > k8sgptConfig.Spec.AI.BackOff.MaxRetries { allowBackendAIRequest = false - fmt.Printf("Disabled AI backend %s due to failures exceeding max retries\n", k8sgptConfig.Spec.AI.Backend) + log.Info(fmt.Sprintf("Disabled AI backend %s due to failures exceeding max retries", k8sgptConfig.Spec.AI.Backend)) analysisRetryCount = 0 } analysisRetryCount++ @@ -265,7 +268,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } // Reset analysisRetryCount analysisRetryCount = 0 @@ -290,7 +293,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } // Prior to creating or updating any results we will delete any stale results that // no longer are relevent, we can do this by using the resultSpec composed name against @@ -304,19 +307,19 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } if len(resultList.Items) > 0 { // If the result does not exist in the map we will delete it for _, result := range resultList.Items { - fmt.Printf("Checking if %s is still relevant\n", result.Name) + log.Info(fmt.Sprintf("Checking if %s is still relevant", result.Name)) if _, ok := rawResults[result.Name]; !ok { err = r.Delete(ctx, &result) if err != nil { k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } else { k8sgptNumberOfResultsByType.With(prometheus.Labels{ "kind": result.Spec.Kind, @@ -335,7 +338,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } // Update metrics @@ -346,9 +349,8 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr "k8sgpt": k8sgptConfig.Name, }).Inc() } else if operation == resources.UpdatedResult { - fmt.Printf("Updated successfully %s \n", result.Name) + log.Info(fmt.Sprintf("Updated successfully %s", result.Name)) } - } // We emit when result Status is not historical @@ -358,10 +360,10 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr "k8sgpts.k8sgpt.ai/name": k8sgptConfig.Name, "k8sgpts.k8sgpt.ai/namespace": k8sgptConfig.Namespace, })); err != nil { - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } if len(latestResultList.Items) == 0 { - return r.finishReconcile(nil, false) + return r.finishReconcile(log, nil, false) } sinkEnabled := k8sgptConfig.Spec.Sink != nil && k8sgptConfig.Spec.Sink.Type != "" && (k8sgptConfig.Spec.Sink.Endpoint != "" || k8sgptConfig.Spec.Sink.Secret != nil) @@ -380,7 +382,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(fmt.Errorf("could not find sink secret: %w", err), false) + return r.finishReconcile(log, fmt.Errorf("could not find sink secret: %w", err), false) } sinkSecretValue = string(secret.Data[k8sgptConfig.Spec.Sink.Secret.Key]) @@ -392,7 +394,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr for _, result := range latestResultList.Items { var res corev1alpha1.Result if err := r.Get(ctx, client.ObjectKey{Namespace: result.Namespace, Name: result.Name}, &res); err != nil { - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } if sinkEnabled { @@ -401,7 +403,7 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } res.Status.Webhook = k8sgptConfig.Spec.Sink.Endpoint } @@ -413,12 +415,12 @@ func (r *K8sGPTReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr k8sgptReconcileErrorCount.With(prometheus.Labels{ "k8sgpt": k8sgptConfig.Name, }).Inc() - return r.finishReconcile(err, false) + return r.finishReconcile(log, err, false) } } } - return r.finishReconcile(nil, false) + return r.finishReconcile(log, nil, false) } // SetupWithManager sets up the controller with the Manager. @@ -435,20 +437,20 @@ func (r *K8sGPTReconciler) SetupWithManager(mgr ctrl.Manager) error { return c } -func (r *K8sGPTReconciler) finishReconcile(err error, requeueImmediate bool) (ctrl.Result, error) { +func (r *K8sGPTReconciler) finishReconcile(logger logr.Logger, err error, requeueImmediate bool) (ctrl.Result, error) { if err != nil { interval := ReconcileErrorInterval if requeueImmediate { interval = 0 } - fmt.Printf("Finished Reconciling k8sGPT with error: %s\n", err.Error()) + logger.Error(err, "Finished Reconciling k8sGPT with error") return ctrl.Result{Requeue: true, RequeueAfter: interval}, err } interval := ReconcileSuccessInterval if requeueImmediate { interval = 0 } - fmt.Println("Finished Reconciling k8sGPT") + logger.Info("Finished Reconciling k8sGPT") return ctrl.Result{Requeue: true, RequeueAfter: interval}, nil } diff --git a/pkg/client/client.go b/pkg/client/client.go index 6def142a..adf94af9 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -24,6 +24,7 @@ import ( "google.golang.org/grpc" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" ) // This is the client for communicating with the K8sGPT in cluster deployment @@ -68,7 +69,9 @@ func GenerateAddress(ctx context.Context, cli client.Client, k8sgptConfig *v1alp } } - fmt.Printf("Creating new client for %s\n", address) + log := log.FromContext(ctx) + log.Info(fmt.Sprintf("Creating new client for %s", address)) + // Test if the port is open conn, err := net.DialTimeout("tcp", address, 1*time.Second) if err != nil { @@ -76,8 +79,8 @@ func GenerateAddress(ctx context.Context, cli client.Client, k8sgptConfig *v1alp } defer conn.Close() - fmt.Printf("Connection established between %s and localhost with time out of %d seconds.\n", address, int64(1)) - fmt.Printf("Remote Address : %s \n", conn.RemoteAddr().String()) + log.WithValues("Remote Address", conn.RemoteAddr().String()). + Info(fmt.Sprintf("Connection established between %s and localhost with time out of %d seconds.", address, int64(1))) return address, nil } diff --git a/pkg/client/integration.go b/pkg/client/integration.go index b1180d81..32989fc7 100644 --- a/pkg/client/integration.go +++ b/pkg/client/integration.go @@ -6,10 +6,11 @@ import ( rpc "buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go/schema/v1/schemav1grpc" schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1" + "github.com/go-logr/logr" "github.com/k8sgpt-ai/k8sgpt-operator/api/v1alpha1" ) -func (c *Client) AddIntegration(config *v1alpha1.K8sGPT) error { +func (c *Client) AddIntegration(logger logr.Logger, config *v1alpha1.K8sGPT) error { // Check if the integration is active already client := rpc.NewServerServiceClient(c.conn) @@ -22,7 +23,7 @@ func (c *Client) AddIntegration(config *v1alpha1.K8sGPT) error { } if resp.Trivy.Enabled == config.Spec.Integrations.Trivy.Enabled { - fmt.Println("Skipping trivy installation, already enabled") + logger.Info("Skipping trivy installation, already enabled") return nil } // If the integration is inactive, make it active diff --git a/pkg/integrations/integrations.go b/pkg/integrations/integrations.go index caa077b4..b1ddc2c0 100644 --- a/pkg/integrations/integrations.go +++ b/pkg/integrations/integrations.go @@ -12,6 +12,7 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" cmdutil "k8s.io/kubectl/pkg/cmd/util" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" ) const ( @@ -37,13 +38,15 @@ func NewIntegrations(client client.Client, ctx context.Context) (*Integrations, } func (i *Integrations) BackstageLabel(result v1alpha1.ResultSpec) map[string]string { + log := log.FromContext(i.ctx, "result", result) + namespace, resourceName, _ := strings.Cut(result.Name, "/") // Log and don't propagate errors so we won't trigger a new reconciliation gvr, err := i.restMapper.ResourceFor(schema.GroupVersionResource{ Resource: result.Kind, }) if err != nil { - fmt.Printf("Unable to find Kind '%s'\n", result.Kind) + log.Error(err, "Unable to find GVR for Kind", "kind", result.Kind) return map[string]string{} } @@ -58,13 +61,13 @@ func (i *Integrations) BackstageLabel(result v1alpha1.ResultSpec) map[string]str err = i.client.Get(i.ctx, client.ObjectKey{Name: resourceName, Namespace: namespace}, obj) // if we don't find the K8s object we won't trigger a new reconciliation and just log a message if err != nil { - fmt.Printf("Fail to retrieve resource %s for namespace %s\n", resourceName, namespace) + log.Error(err, "Fail to retrieve resource", "resource", resourceName, "namespace", namespace) return map[string]string{} } labels := obj.GetLabels() value, exists := labels[backstageLabelKey] if !exists { - fmt.Printf("Label key '%s' does not exist in %s resource: %s\n", backstageLabelKey, result.Kind, resourceName) + log.Info(fmt.Sprintf("Label key '%s' does not exist in %s resource: %s", backstageLabelKey, result.Kind, resourceName)) } // Assign the same label key/value to result CR return map[string]string{backstageLabelKey: value} diff --git a/pkg/resources/results.go b/pkg/resources/results.go index f4008468..c85f0140 100644 --- a/pkg/resources/results.go +++ b/pkg/resources/results.go @@ -11,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" ) type ResultOperation string @@ -63,6 +64,7 @@ func GetResult(resultSpec v1alpha1.ResultSpec, name, namespace, backend string, } } func CreateOrUpdateResult(ctx context.Context, c client.Client, res v1alpha1.Result) (ResultOperation, error) { + log := log.FromContext(ctx) var existing v1alpha1.Result if err := c.Get(ctx, client.ObjectKey{Namespace: res.Namespace, Name: res.Name}, &existing); err != nil { if !errors.IsNotFound(err) { @@ -71,7 +73,7 @@ func CreateOrUpdateResult(ctx context.Context, c client.Client, res v1alpha1.Res if err := c.Create(ctx, &res); err != nil { return NoOpResult, err } - fmt.Printf("Created result %s\n", res.Name) + log.Info(fmt.Sprintf("Created result %s", res.Name)) return CreatedResult, nil } if len(existing.Spec.Error) == len(res.Spec.Error) && reflect.DeepEqual(res.Labels, existing.Labels) { @@ -89,6 +91,6 @@ func CreateOrUpdateResult(ctx context.Context, c client.Client, res v1alpha1.Res if err := c.Status().Update(ctx, &existing); err != nil { return NoOpResult, err } - fmt.Printf("Updated result %s\n", res.Name) + log.Info(fmt.Sprintf("Updated result %s", res.Name)) return UpdatedResult, nil }