From 560a6fcbea9114c9f37bc616a47848b698d5e006 Mon Sep 17 00:00:00 2001 From: Mickael Stanislas Date: Thu, 17 Oct 2024 09:09:25 +0200 Subject: [PATCH] chore: new log library (#49) --- cmd/admission-controller/certificate.go | 20 --- cmd/admission-controller/main.go | 27 ++- .../webhook-configuration.go | 12 +- cmd/admission-controller/webhook.go | 45 +++-- cmd/kimup/event.go | 31 +++- cmd/kimup/main.go | 25 ++- cmd/kimup/scheduler.go | 1 + cmd/operator/main.go | 156 +++++++---------- go.mod | 29 +--- go.sum | 59 +------ internal/actions/action_alert_common.go | 5 +- internal/actions/action_alert_discord.go | 6 +- internal/actions/action_alert_email.go | 3 + internal/controller/image_controller.go | 22 ++- internal/controller/kimup_controller.go | 77 +++++++-- internal/controller/resources_admission.go | 2 +- internal/kubeclient/client.go | 2 - internal/kubeclient/image.go | 4 +- internal/log/log.go | 160 ++++++++++++++++++ internal/models/log.go | 4 +- internal/rules/rules.go | 5 +- internal/rules/semver.go | 15 +- internal/triggers/crontab/crontab.go | 16 +- internal/triggers/triggers.go | 11 +- internal/utils/log.go | 23 --- 25 files changed, 424 insertions(+), 336 deletions(-) create mode 100644 internal/log/log.go diff --git a/cmd/admission-controller/certificate.go b/cmd/admission-controller/certificate.go index 6ff1e2f..324bc51 100644 --- a/cmd/admission-controller/certificate.go +++ b/cmd/admission-controller/certificate.go @@ -43,13 +43,11 @@ func generateTLS() (keyPair tls.Certificate, caPEM *bytes.Buffer, err error) { caPEM, certPEM, certKeyPEM, err := generateCert([]string{webhookBase}, dnsNames, commonName) if err != nil { - errorLogger.Printf("Failed to generate ca and certificate key pair: %v", err) return } keyPair, err = tls.X509KeyPair(certPEM.Bytes(), certKeyPEM.Bytes()) if err != nil { - errorLogger.Printf("Failed to load certificate key pair: %v", err) return } return @@ -76,14 +74,12 @@ func generateCert(orgs, dnsNames []string, commonName string) (caPEM, newCertPEM // generate private key for CA caPrivateKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { - errorLogger.Printf("Failed to generate private key for CA: %v", err) return nil, nil, nil, err } // create the CA certificate caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivateKey.PublicKey, caPrivateKey) if err != nil { - errorLogger.Printf("Failed to create CA certificate: %v", err) return nil, nil, nil, err } @@ -94,7 +90,6 @@ func generateCert(orgs, dnsNames []string, commonName string) (caPEM, newCertPEM Bytes: caBytes, }) if err != nil { - errorLogger.Printf("Failed to encode CA certificate: %v", err) return nil, nil, nil, err } @@ -103,8 +98,6 @@ func generateCert(orgs, dnsNames []string, commonName string) (caPEM, newCertPEM writeNewCA(caPEM, manifestWebhookPath) time.Sleep(2 * time.Second) applyManifest(manifestWebhookPath) - - // debugLogger.Printf("CA certificate Encoded: %s", base64.StdEncoding.EncodeToString(caPEM.Bytes())) } // new certificate config @@ -124,14 +117,12 @@ func generateCert(orgs, dnsNames []string, commonName string) (caPEM, newCertPEM // generate new private key newPrivateKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { - errorLogger.Printf("Failed to generate private key for new certificate: %v", err) return nil, nil, nil, err } // sign the new certificate newCertBytes, err := x509.CreateCertificate(rand.Reader, newCert, ca, &newPrivateKey.PublicKey, caPrivateKey) if err != nil { - errorLogger.Printf("Failed to create new certificate: %v", err) return nil, nil, nil, err } @@ -142,7 +133,6 @@ func generateCert(orgs, dnsNames []string, commonName string) (caPEM, newCertPEM Bytes: newCertBytes, }) if err != nil { - errorLogger.Printf("Failed to encode new certificate: %v", err) return nil, nil, nil, err } @@ -153,7 +143,6 @@ func generateCert(orgs, dnsNames []string, commonName string) (caPEM, newCertPEM Bytes: x509.MarshalPKCS1PrivateKey(newPrivateKey), }) if err != nil { - errorLogger.Printf("Failed to encode new private key: %v", err) return nil, nil, nil, err } @@ -166,7 +155,6 @@ func writeNewCA(caPEM *bytes.Buffer, filePath string) { // Lire le fichier file, err := os.Open(filePath) if err != nil { - warningLogger.Printf("Failed to open file: %v\n", err) return } defer file.Close() @@ -182,14 +170,12 @@ func writeNewCA(caPEM *bytes.Buffer, filePath string) { } if err := scanner.Err(); err != nil { - warningLogger.Printf("Failed to read file: %v\n", err) return } // Écrire les modifications dans le fichier file, err = os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0o644) if err != nil { - warningLogger.Printf("Failed to open file: %v\n", err) return } defer file.Close() @@ -198,7 +184,6 @@ func writeNewCA(caPEM *bytes.Buffer, filePath string) { for _, line := range lines { _, err := writer.WriteString(line + "\n") if err != nil { - warningLogger.Printf("Failed to write to file: %v\n", err) return } } @@ -209,7 +194,6 @@ func applyManifest(file string) { // read the manifest file manifestBytes, err := os.ReadFile(file) if err != nil { - warningLogger.Printf("Failed to read manifest: %v\n", err) return } @@ -218,14 +202,12 @@ func applyManifest(file string) { obj := &unstructured.Unstructured{} _, _, err = decoder.Decode(manifestBytes, nil, obj) if err != nil { - warningLogger.Printf("Failed to decode manifest: %v\n", err) return } // convert the unstructured object to typed object mutatingWebhookConfiguration, err := kubeclient.DecodeUnstructured[v1.MutatingWebhookConfigurationApplyConfiguration](obj) if err != nil { - warningLogger.Printf("Failed to decode manifest: %v\n", err) return } @@ -235,8 +217,6 @@ func applyManifest(file string) { &mutatingWebhookConfiguration, metav1.ApplyOptions{Force: true, FieldManager: "kumi-webhook"}, ); err != nil { - warningLogger.Printf("Failed to apply manifest: %v\n", err) return } - infoLogger.Printf("Successfully applied manifest: %s", file) } diff --git a/cmd/admission-controller/main.go b/cmd/admission-controller/main.go index eacff39..7da812c 100644 --- a/cmd/admission-controller/main.go +++ b/cmd/admission-controller/main.go @@ -4,7 +4,6 @@ import ( "context" "crypto/tls" "flag" - "log" "net" "os" "os/signal" @@ -12,20 +11,18 @@ import ( "time" "github.com/prometheus/client_golang/prometheus" + "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" "github.com/orange-cloudavenue/kube-image-updater/internal/httpserver" client "github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" "github.com/orange-cloudavenue/kube-image-updater/internal/metrics" ) var ( insideCluster bool = true // running inside k8s cluster - debugLogger *log.Logger - infoLogger *log.Logger - warningLogger *log.Logger - errorLogger *log.Logger webhookNamespace string = "example.com" webhookServiceName string = "your" @@ -49,12 +46,6 @@ var ( ) func init() { - // init loggers - debugLogger = log.New(os.Stderr, "DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile) - infoLogger = log.New(os.Stderr, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) - warningLogger = log.New(os.Stderr, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile) - errorLogger = log.New(os.Stderr, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) - // webhook server running namespace (default to "default") if os.Getenv("POD_NAMESPACE") != "" { webhookNamespace = os.Getenv("POD_NAMESPACE") @@ -82,14 +73,14 @@ func main() { // kubernetes golang library provide flag "kubeconfig" to specify the path to the kubeconfig file kubeClient, err = client.New(flag.Lookup("kubeconfig").Value.String()) if err != nil { - log.Panicf("Error creating kubeclient: %v", err) + log.WithError(err).Panicf("Error creating kubeclient") } // * Webhook server // generate cert for webhook pair, caPEM, err := generateTLS() if err != nil { - errorLogger.Fatalf("Failed to generate TLS pair: %v", err) + log.WithError(err).Fatal("Failed to generate TLS") } tlsC := &tls.Config{ Certificates: []tls.Certificate{pair}, @@ -100,7 +91,7 @@ func main() { // create or update the mutatingwebhookconfiguration err = createOrUpdateMutatingWebhookConfiguration(caPEM, webhookServiceName, webhookNamespace, kubeClient) if err != nil { - errorLogger.Printf("Failed to create or update the mutating webhook configuration: %v", err) + log.WithError(err).Error("Failed to create or update the mutating webhook configuration") signalChan <- os.Interrupt } @@ -116,11 +107,15 @@ func main() { s, err := a.Add("webhook", httpserver.WithTLS(tlsC), httpserver.WithAddr(webhookPort)) if err != nil { - errorLogger.Fatalf("Failed to create the server: %v", err) + log. + WithError(err). + WithFields(logrus.Fields{ + "address": webhookPort, + }).Fatal("Failed to create the server") } s.Config.Post(webhookPathMutate, ServeHandler) if err := a.Run(); err != nil { - errorLogger.Fatalf("Failed to start HTTP servers: %v", err) + log.WithError(err).Fatal("Failed to start HTTP servers") } // !-- OS signal handling --! // diff --git a/cmd/admission-controller/webhook-configuration.go b/cmd/admission-controller/webhook-configuration.go index 3250340..d479465 100644 --- a/cmd/admission-controller/webhook-configuration.go +++ b/cmd/admission-controller/webhook-configuration.go @@ -10,14 +10,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" client "github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" ) // createOrUpdateMutatingWebhookConfiguration creates or updates the mutating webhook configuration // for the webhook service. The CA is generated and used for the webhook. // This function create the request to the Kubernetes API server to create or update the mutating webhook configuration. func createOrUpdateMutatingWebhookConfiguration(caPEM *bytes.Buffer, webhookService, webhookNamespace string, k client.Interface) error { - infoLogger.Println("Initializing the kube client...") - mutatingWebhookConfigV1Client := k.AdmissionregistrationV1() var clientConfig admissionregistrationv1.WebhookClientConfig @@ -42,8 +41,7 @@ func createOrUpdateMutatingWebhookConfiguration(caPEM *bytes.Buffer, webhookServ URL: &url, } } - - infoLogger.Printf("Creating or updating the mutatingwebhookconfiguration: %s", webhookConfigName) + log.Debug("Creating or updating the mutatingwebhookconfiguration") fail := admissionregistrationv1.Fail sideEffect := admissionregistrationv1.SideEffectClassNone mutatingWebhookConfig := &admissionregistrationv1.MutatingWebhookConfiguration{ @@ -77,12 +75,9 @@ func createOrUpdateMutatingWebhookConfiguration(caPEM *bytes.Buffer, webhookServ switch { case err != nil && apierrors.IsNotFound(err): if _, err := mutatingWebhookConfigV1Client.MutatingWebhookConfigurations().Create(context.TODO(), mutatingWebhookConfig, metav1.CreateOptions{}); err != nil { - warningLogger.Printf("Failed to update the mutatingwebhookconfiguration: %s", webhookConfigName) return err } - infoLogger.Printf("Created mutatingwebhookconfiguration: %s", webhookConfigName) case err != nil: - warningLogger.Printf("Failed to check the mutatingwebhookconfiguration: %s", webhookConfigName) return err default: // there is an existing mutatingWebhookConfiguration @@ -98,12 +93,9 @@ func createOrUpdateMutatingWebhookConfiguration(caPEM *bytes.Buffer, webhookServ reflect.DeepEqual(foundWebhookConfig.Webhooks[0].ClientConfig.URL, mutatingWebhookConfig.Webhooks[0].ClientConfig.URL)) { mutatingWebhookConfig.ObjectMeta.ResourceVersion = foundWebhookConfig.ObjectMeta.ResourceVersion if _, err := mutatingWebhookConfigV1Client.MutatingWebhookConfigurations().Update(context.TODO(), mutatingWebhookConfig, metav1.UpdateOptions{}); err != nil { - warningLogger.Printf("Failed to update the mutatingwebhookconfiguration: %s", webhookConfigName) return err } - infoLogger.Printf("Updated the mutatingwebhookconfiguration: %s", webhookConfigName) } - infoLogger.Printf("The mutatingwebhookconfiguration: %s already exists and has no change", webhookConfigName) } return nil diff --git a/cmd/admission-controller/webhook.go b/cmd/admission-controller/webhook.go index e8f7a1e..da32d88 100644 --- a/cmd/admission-controller/webhook.go +++ b/cmd/admission-controller/webhook.go @@ -8,12 +8,14 @@ import ( "net/http" "github.com/prometheus/client_golang/prometheus" + "github.com/sirupsen/logrus" admissionv1 "k8s.io/api/admission/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" "github.com/orange-cloudavenue/kube-image-updater/internal/annotations" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" "github.com/orange-cloudavenue/kube-image-updater/internal/patch" ) @@ -33,7 +35,7 @@ func ServeHandler(w http.ResponseWriter, r *http.Request) { } if len(body) == 0 { promHTTPErrorsTotal.Inc() - warningLogger.Println("empty body") + log.Error("empty body") http.Error(w, "empty body", http.StatusBadRequest) return } @@ -42,7 +44,6 @@ func ServeHandler(w http.ResponseWriter, r *http.Request) { contentType := r.Header.Get("Content-Type") if contentType != "application/json" { promHTTPErrorsTotal.Inc() - warningLogger.Printf("Content-Type=%s, expect application/json", contentType) http.Error(w, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType) return } @@ -51,7 +52,7 @@ func ServeHandler(w http.ResponseWriter, r *http.Request) { ar := admissionv1.AdmissionReview{} if _, _, err := deserializer.Decode(body, nil, &ar); err != nil { promHTTPErrorsTotal.Inc() - warningLogger.Printf("Can't decode body: %v", err) + log.WithError(err).Warn("Can't decode body") admissionResponse = &admissionv1.AdmissionResponse{ Result: &metav1.Status{ Message: err.Error(), @@ -77,13 +78,10 @@ func ServeHandler(w http.ResponseWriter, r *http.Request) { resp, err := json.Marshal(admissionReview) if err != nil { promHTTPErrorsTotal.Inc() - warningLogger.Printf("Can't encode response: %v", err) http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError) } - infoLogger.Printf("Ready to write response ...") if _, err := w.Write(resp); err != nil { promHTTPErrorsTotal.Inc() - warningLogger.Printf("Can't write response: %v", err) http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError) } } @@ -93,7 +91,6 @@ func mutate(ctx context.Context, ar *admissionv1.AdmissionReview) *admissionv1.A req := ar.Request var pod corev1.Pod if err := json.Unmarshal(req.Object.Raw, &pod); err != nil { - warningLogger.Printf("Could not unmarshal raw object: %v", err) return &admissionv1.AdmissionResponse{ Result: &metav1.Status{ Message: err.Error(), @@ -101,8 +98,14 @@ func mutate(ctx context.Context, ar *admissionv1.AdmissionReview) *admissionv1.A } } - infoLogger.Printf("AdmissionReview for Kind=%v, Namespace=%v Name=%v (%v) UID=%v patchOperation=%v UserInfo=%v", - req.Kind, req.Namespace, req.Name, pod.Name, req.UID, req.Operation, req.UserInfo) + log.WithFields(logrus.Fields{ + "Kind": req.Kind, + "Namespace": req.Namespace, + "Name": req.Name, + "UID": req.UID, + "Operation": req.Operation, + "UserInfo": req.UserInfo, + }).Info("AdmissionReview") // create patch patchBytes, err := createPatch(ctx, &pod) @@ -113,7 +116,6 @@ func mutate(ctx context.Context, ar *admissionv1.AdmissionReview) *admissionv1.A }, } } - infoLogger.Printf("AdmissionResponse: patch=%v\n", string(patchBytes)) return &admissionv1.AdmissionResponse{ Allowed: true, Patch: patchBytes, @@ -136,7 +138,11 @@ func createPatch(ctx context.Context, pod *corev1.Pod) ([]byte, error) { // var patch []patchOperation p := patch.NewBuilder() - infoLogger.Printf("Generate Patch for: %v\n", pod.Name) + log. + WithFields(logrus.Fields{ + "Namespace": pod.Namespace, + "Name": pod.Name, + }).Info("Generate Patch") for i, container := range pod.Spec.Containers { // check if an annotation exist @@ -148,13 +154,24 @@ func createPatch(ctx context.Context, pod *corev1.Pod) ([]byte, error) { // find the image associated with the pod image, err = kubeClient.Image().Find(ctx, pod.Namespace, container.Image) if err != nil { - warningLogger.Printf("No associated kind Image found: %v", err) + log. + WithFields(logrus.Fields{ + "Namespace": pod.Namespace, + "Name": pod.Name, + "Container": container.Name, + }). + WithError(err).Error("Failed to find kind Image") continue } } else { image, err = kubeClient.Image().Get(ctx, pod.Namespace, crdName) if err != nil { - warningLogger.Printf("Failed to get kind Image: %v", err) + log. + WithFields(logrus.Fields{ + "Namespace": pod.Namespace, + "Name": pod.Name, + "Container": container.Name, + }).WithError(err).Error("Failed to get kind Image") continue } } @@ -173,7 +190,5 @@ func createPatch(ctx context.Context, pod *corev1.Pod) ([]byte, error) { // update the annotation p.AddRawPatches(an.Containers().BuildPatches()) - debugLogger.Printf("Patch created: %v\n", p) - return p.Generate() } diff --git a/cmd/kimup/event.go b/cmd/kimup/event.go index 68a3f5a..d29b745 100644 --- a/cmd/kimup/event.go +++ b/cmd/kimup/event.go @@ -3,12 +3,13 @@ package main import ( "context" - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" "github.com/orange-cloudavenue/kube-image-updater/internal/actions" "github.com/orange-cloudavenue/kube-image-updater/internal/annotations" "github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" "github.com/orange-cloudavenue/kube-image-updater/internal/models" "github.com/orange-cloudavenue/kube-image-updater/internal/triggers" "github.com/orange-cloudavenue/kube-image-updater/internal/triggers/crontab" @@ -21,7 +22,13 @@ func setupTriggers(x *v1alpha1.Image) { case triggers.Crontab: if ok, err := crontab.IsExistingJob(crontab.BuildKey(x.Namespace, x.Name)); err != nil || !ok { if err := crontab.AddCronTab(x.Namespace, x.Name, trigger.Value); err != nil { - log.Errorf("Error adding cronjob: %v", err) + log. + WithError(err). + WithFields(logrus.Fields{ + "crontab": trigger.Value, + "namespace": x.Namespace, + "name": x.Name, + }).Error("Error adding cronjob") } } case triggers.Webhook: @@ -36,7 +43,12 @@ func cleanTriggers(x *v1alpha1.Image) { case triggers.Crontab: if ok, err := crontab.IsExistingJob(crontab.BuildKey(x.Namespace, x.Name)); err != nil || ok { if err := crontab.RemoveJob(crontab.BuildKey(x.Namespace, x.Name)); err != nil { - log.Errorf("Error removing crontab: %v", err) + log. + WithError(err). + WithFields(logrus.Fields{ + "namespace": x.Namespace, + "name": x.Name, + }).Error("Error removing crontab") } } case triggers.Webhook: @@ -48,10 +60,19 @@ func cleanTriggers(x *v1alpha1.Image) { func refreshIfRequired(an annotations.Annotation, image v1alpha1.Image) { if an.Action().Get() == annotations.ActionRefresh { // * Here is only if the image has annotations.ActionRefresh - log.Infof("[Fire] Annotation trigger refresh for image %s in namespace %s", image.Name, image.Namespace) + log. + WithFields(logrus.Fields{ + "namespace": image.Namespace, + "name": image.Name, + }).Info("Annotation trigger refresh") _, err := triggers.Trigger(triggers.RefreshImage, image.Namespace, image.Name) if err != nil { - log.Errorf("Error triggering event: %v", err) + log. + WithFields(logrus.Fields{ + "namespace": image.Namespace, + "name": image.Name, + }). + Error("Error triggering event") } an.Remove(annotations.KeyAction) } diff --git a/cmd/kimup/main.go b/cmd/kimup/main.go index 1ae4270..fd04eb0 100644 --- a/cmd/kimup/main.go +++ b/cmd/kimup/main.go @@ -9,14 +9,12 @@ import ( "syscall" "time" - log "github.com/sirupsen/logrus" - "github.com/orange-cloudavenue/kube-image-updater/internal/annotations" "github.com/orange-cloudavenue/kube-image-updater/internal/httpserver" "github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" "github.com/orange-cloudavenue/kube-image-updater/internal/models" "github.com/orange-cloudavenue/kube-image-updater/internal/triggers" - "github.com/orange-cloudavenue/kube-image-updater/internal/utils" ) var ( @@ -26,23 +24,20 @@ var ( ) func init() { - flag.String("loglevel", "info", "log level (debug, info, warn, error, fatal, panic)") // TODO add namespace scope + // Flag "loglevel" is set in log package flag.Parse() - - log.SetLevel(utils.ParseLogLevel(flag.Lookup("loglevel").Value.String())) - log.SetFormatter(&log.TextFormatter{}) } func main() { signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) - log.Infof("Starting kimup (version: %s)", version) + log.WithField("version", version).Info("Starting kimup", version) // kubernetes golang library provide flag "kubeconfig" to specify the path to the kubeconfig file k, err := kubeclient.New(flag.Lookup("kubeconfig").Value.String()) if err != nil { - log.Panicf("Error creating kubeclient: %v", err) + log.WithError(err).Panic("Error creating kubeclient") } ctx, cancel := context.WithCancel(context.Background()) @@ -60,7 +55,7 @@ func main() { })) if err := a.Run(); err != nil { - log.Errorf("Failed to start HTTP servers: %v", err) + log.WithError(err).Error("Failed to start HTTP servers") // send signal to stop the program c <- syscall.SIGINT } @@ -70,7 +65,7 @@ func main() { go func() { x, err := k.Image().Watch(ctx) if err != nil { - log.Panicf("Error watching events: %v", err) + log.WithError(err).Panic("Error watching events") } for { @@ -95,11 +90,11 @@ func main() { setupTriggers(&event.Value) refreshIfRequired(an, event.Value) if err := setTagIfNotExists(ctx, k, an, &event.Value); err != nil { - log.Errorf("Error setting tag: %v", err) + log.WithError(err).Error("Error setting tag") } if err := k.Image().Update(ctx, event.Value); err != nil { - log.Errorf("Error updating image: %v", err) + log.WithError(err).Error("Error updating image") } case "MODIFIED": @@ -112,7 +107,7 @@ func main() { case triggers.Crontab: cleanTriggers(&event.Value) case triggers.Webhook: - log.Info("Webhook trigger not implemented yet") + log.Warn("Webhook trigger not implemented yet") } } @@ -123,7 +118,7 @@ func main() { refreshIfRequired(an, event.Value) if err := k.Image().Update(ctx, event.Value); err != nil { - log.Errorf("Error updating image: %v", err) + log.WithError(err).Error("Error updating image") } setupTriggers(&event.Value) diff --git a/cmd/kimup/scheduler.go b/cmd/kimup/scheduler.go index f00a51f..955ba38 100644 --- a/cmd/kimup/scheduler.go +++ b/cmd/kimup/scheduler.go @@ -26,6 +26,7 @@ func initScheduler(ctx context.Context, k kubeclient.Interface) { // Start Crontab client crontab.New(ctx) + // Add event lock event.On(triggers.RefreshImage.String(), event.ListenerFunc(func(e event.Event) (err error) { if l[e.Data()["namespace"].(string)+"/"+e.Data()["image"].(string)] == nil { l[e.Data()["namespace"].(string)+"/"+e.Data()["image"].(string)] = &sync.RWMutex{} diff --git a/cmd/operator/main.go b/cmd/operator/main.go index cd0baeb..c51c493 100644 --- a/cmd/operator/main.go +++ b/cmd/operator/main.go @@ -17,23 +17,28 @@ limitations under the License. package main import ( - "crypto/tls" + "context" "flag" + "net" "os" + "os/signal" + "syscall" + "time" + "github.com/bombsimon/logrusr/v4" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - "sigs.k8s.io/controller-runtime/pkg/metrics/filters" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - "sigs.k8s.io/controller-runtime/pkg/webhook" kimupv1alpha1 "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" "github.com/orange-cloudavenue/kube-image-updater/internal/controller" + "github.com/orange-cloudavenue/kube-image-updater/internal/httpserver" "github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" + "github.com/orange-cloudavenue/kube-image-updater/internal/models" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -41,8 +46,8 @@ import ( ) var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") + scheme = runtime.NewScheme() + c = make(chan os.Signal, 1) ) func init() { @@ -53,101 +58,36 @@ func init() { } func main() { - var metricsAddr string + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + var enableLeaderElection bool - var probeAddr string - var secureMetrics bool - var enableHTTP2 bool - var tlsOpts []func(*tls.Config) - flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ - "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") - flag.BoolVar(&secureMetrics, "metrics-secure", true, - "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.") - flag.BoolVar(&enableHTTP2, "enable-http2", false, - "If set, HTTP/2 will be enabled for the metrics and webhook servers") - opts := zap.Options{ - Development: true, - } - opts.BindFlags(flag.CommandLine) flag.Parse() - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - - // if the enable-http2 flag is false (the default), http/2 should be disabled - // due to its vulnerabilities. More specifically, disabling http/2 will - // prevent from being vulnerable to the HTTP/2 Stream Cancellation and - // Rapid Reset CVEs. For more information see: - // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 - // - https://github.com/advisories/GHSA-4374-p667-p6c8 - disableHTTP2 := func(c *tls.Config) { - setupLog.Info("disabling http/2") - c.NextProtos = []string{"http/1.1"} - } - - if !enableHTTP2 { - tlsOpts = append(tlsOpts, disableHTTP2) - } - - webhookServer := webhook.NewServer(webhook.Options{ - TLSOpts: tlsOpts, - }) - - // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server. - // More info: - // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/server - // - https://book.kubebuilder.io/reference/metrics.html - metricsServerOptions := metricsserver.Options{ - BindAddress: metricsAddr, - SecureServing: secureMetrics, - // TODO(user): TLSOpts is used to allow configuring the TLS config used for the server. If certificates are - // not provided, self-signed certificates will be generated by default. This option is not recommended for - // production environments as self-signed certificates do not offer the same level of trust and security - // as certificates issued by a trusted Certificate Authority (CA). The primary risk is potentially allowing - // unauthorized access to sensitive metrics data. Consider replacing with CertDir, CertName, and KeyName - // to provide certificates, ensuring the server communicates using trusted and secure certificates. - TLSOpts: tlsOpts, - } - - if secureMetrics { - // FilterProvider is used to protect the metrics endpoint with authn/authz. - // These configurations ensure that only authorized users and service accounts - // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info: - // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/filters#WithAuthenticationAndAuthorization - metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization - } + ctrl.SetLogger(logrusr.New(log.GetLogger())) mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - Metrics: metricsServerOptions, - WebhookServer: webhookServer, - HealthProbeBindAddress: probeAddr, + Scheme: scheme, + Metrics: metricsserver.Options{ + // TODO pass metrics to common metrics server + BindAddress: "0", // disable metrics service + }, + // TODO reenable and use comman healthz server to check the health of the application + HealthProbeBindAddress: "0", // disable health probe service LeaderElection: enableLeaderElection, LeaderElectionID: "71be4586.cloudavenue.io", - // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily - // when the Manager ends. This requires the binary to immediately end when the - // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly - // speeds up voluntary leader transitions as the new leader don't have to wait - // LeaseDuration time first. - // - // In the default scaffold provided, the program ends immediately after - // the manager stops, so would be fine to enable this option. However, - // if you are doing or is intended to do any operation such as perform cleanups - // after the manager stops then its usage might be unsafe. - // LeaderElectionReleaseOnCancel: true, }) if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) + log.WithError(err).Error("unable to start manager") + c <- syscall.SIGINT } kubeAPIClient, err := kubeclient.NewFromRestConfig(ctrl.GetConfigOrDie()) if err != nil { - setupLog.Error(err, "unable to create kubeclient") - os.Exit(1) + log.WithError(err).Error("unable to create kubeclient") + c <- syscall.SIGINT } if err = (&controller.ImageReconciler{ @@ -156,8 +96,8 @@ func main() { Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("kimup-operator"), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Image") - os.Exit(1) + log.WithError(err).Error("unable to create controller", "controller", "Image") + c <- syscall.SIGINT } if err = (&controller.KimupReconciler{ @@ -166,24 +106,48 @@ func main() { Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("kimup-operator"), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Kimup") - os.Exit(1) + log.WithError(err).Error(err, "unable to create controller", "controller", "Kimup") + c <- syscall.SIGINT } // +kubebuilder:scaffold:builder + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // * Config the metrics and healthz server + a, waitHTTP := httpserver.Init(ctx, httpserver.WithCustomHandlerForHealth( + func() (bool, error) { + // TODO improve + _, err := net.DialTimeout("tcp", models.HealthzDefaultAddr, 5*time.Second) + if err != nil { + return false, err + } + return true, nil + })) + + if err := a.Run(); err != nil { + log.WithError(err).Error("Failed to start HTTP servers") + // send signal to stop the program + c <- syscall.SIGINT + } + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up health check") - os.Exit(1) + log.WithError(err).Error(err, "unable to set up health check") + c <- syscall.SIGINT } if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up ready check") - os.Exit(1) + log.WithError(err).Error(err, "unable to set up ready check") + c <- syscall.SIGINT } - setupLog.Info("starting manager") + log.Info("Starting operator") if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) + log.WithError(err).Error(err, "problem running manager") + c <- syscall.SIGINT } + + <-c + cancel() + waitHTTP() } diff --git a/go.mod b/go.mod index 469b588..1256cf0 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ replace github.com/distribution/reference => github.com/distribution/reference v require ( github.com/Masterminds/semver/v3 v3.3.0 + github.com/bombsimon/logrusr/v4 v4.1.0 github.com/containers/image/v5 v5.32.2 github.com/containrrr/shoutrrr v0.8.0 github.com/crazy-max/diun/v4 v4.28.0 @@ -20,6 +21,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 github.com/thanhpk/randstr v1.0.6 + golang.org/x/term v0.23.0 k8s.io/api v0.31.1 k8s.io/apimachinery v0.31.1 k8s.io/client-go v0.31.1 @@ -28,11 +30,7 @@ require ( require ( github.com/BurntSushi/toml v1.4.0 // indirect - github.com/antlr4-go/antlr/v4 v4.13.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/containers/ocicrypt v1.2.0 // indirect @@ -47,11 +45,9 @@ require ( github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fatih/color v1.15.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect @@ -60,16 +56,13 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/cel-go v0.20.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/imdario/mergo v0.3.16 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -89,48 +82,30 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.24.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.31.0 // indirect - k8s.io/apiserver v0.31.0 // indirect - k8s.io/component-base v0.31.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index 169acea..16b01f9 100644 --- a/go.sum +++ b/go.sum @@ -2,16 +2,10 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= -github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/bombsimon/logrusr/v4 v4.1.0 h1:uZNPbwusB0eUXlO8hIUwStE6Lr5bLN6IgYgG+75kuh4= +github.com/bombsimon/logrusr/v4 v4.1.0/go.mod h1:pjfHC5e59CvjTBIU3V3sGhFWFAnsnhOR03TRc6im0l8= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -26,7 +20,6 @@ github.com/containers/storage v1.55.0 h1:wTWZ3YpcQf1F+dSP4KxG9iqDfpQY1otaUXjPpff github.com/containers/storage v1.55.0/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec= github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crazy-max/diun/v4 v4.28.0 h1:3kWWkc6TAII32Mxlc7PMN32IEMYcglms0ycqBSpNtFE= github.com/crazy-max/diun/v4 v4.28.0/go.mod h1:vw/KMvUuaBNolMgwhfib72+neHK+ZOUF6DfmQLDOKbo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -57,19 +50,14 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -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= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -86,8 +74,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= -github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -108,12 +94,8 @@ github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= -github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -177,20 +159,14 @@ github.com/reugn/go-quartz v0.13.0 h1:0eMxvj28Qu1npIDdN9Mzg9hwyksGH6XJt4Cz0QB8EU github.com/reugn/go-quartz v0.13.0/go.mod h1:0ghKksELp8MJ4h84T203aTHRF3Kug5BrxEW3ErBvhzY= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -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/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -208,22 +184,6 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -250,8 +210,6 @@ golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -280,12 +238,6 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -295,7 +247,6 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSP gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -308,20 +259,14 @@ k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24 k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= -k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= -k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= -k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= 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/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/internal/actions/action_alert_common.go b/internal/actions/action_alert_common.go index 84b5ccb..c80c814 100644 --- a/internal/actions/action_alert_common.go +++ b/internal/actions/action_alert_common.go @@ -3,7 +3,8 @@ package actions import ( s "github.com/containrrr/shoutrrr" "github.com/containrrr/shoutrrr/pkg/router" - log "github.com/sirupsen/logrus" + + "github.com/orange-cloudavenue/kube-image-updater/internal/log" ) func newAlertSender(url string) (*router.ServiceRouter, error) { @@ -12,7 +13,7 @@ func newAlertSender(url string) (*router.ServiceRouter, error) { return nil, err } - sender.SetLogger(log.StandardLogger()) + sender.SetLogger(log.GetLogger()) return sender, nil } diff --git a/internal/actions/action_alert_discord.go b/internal/actions/action_alert_discord.go index 7541a15..45b3aac 100644 --- a/internal/actions/action_alert_discord.go +++ b/internal/actions/action_alert_discord.go @@ -6,9 +6,9 @@ import ( "strings" s "github.com/containrrr/shoutrrr" - log "github.com/sirupsen/logrus" "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" "github.com/orange-cloudavenue/kube-image-updater/internal/models" ) @@ -60,8 +60,6 @@ func (a *alertDiscord) Execute(ctx context.Context) error { return fmt.Errorf("error rendering alert message: %v", err) } - log.Debugf("Sending Discord alert") - var bigErr error if errS := sender.Send(message, nil); errS != nil { for _, e := range errS { @@ -73,6 +71,8 @@ func (a *alertDiscord) Execute(ctx context.Context) error { return bigErr } + log.WithField("action", a.GetName()).Info("Alert sent to Discord") + return nil } diff --git a/internal/actions/action_alert_email.go b/internal/actions/action_alert_email.go index d53fd55..aa7d409 100644 --- a/internal/actions/action_alert_email.go +++ b/internal/actions/action_alert_email.go @@ -8,6 +8,7 @@ import ( "github.com/containrrr/shoutrrr/pkg/types" "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" "github.com/orange-cloudavenue/kube-image-updater/internal/models" ) @@ -73,6 +74,8 @@ func (a *alertEmail) Execute(ctx context.Context) error { return bigErr } + log.WithField("action", a.GetName()).Info("alert email sent") + return nil } diff --git a/internal/controller/image_controller.go b/internal/controller/image_controller.go index db20bc6..805228a 100644 --- a/internal/controller/image_controller.go +++ b/internal/controller/image_controller.go @@ -18,17 +18,17 @@ package controller import ( "context" - "fmt" + "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" kimupv1alpha1 "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" "github.com/orange-cloudavenue/kube-image-updater/internal/annotations" "github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" ) // ImageReconciler reconciles a Image object @@ -59,19 +59,23 @@ const ( // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile func (r *ImageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - _ = log.FromContext(ctx) + xlog := log.WithContext(ctx).WithFields(logrus.Fields{ + "namespace": req.Namespace, + "name": req.Name, + }) var image kimupv1alpha1.Image if err := r.Client.Get(ctx, req.NamespacedName, &image); err != nil { - log.Log.Error(err, "unable to fetch Image") + if client.IgnoreNotFound(err) != nil { + xlog.WithError(err).Error("could not get the image object") + } return ctrl.Result{}, client.IgnoreNotFound(err) } an := annotations.New(ctx, &image) - log.Log.Info(fmt.Sprintf("Reconciling Image %s in namespace %s", req.Name, req.Namespace)) - + xlog.Info("Reconciling Image") equal, err := an.CheckSum().IsEqual(image.Spec) if err != nil || !equal { an.Action().Set(annotations.ActionReload) @@ -80,11 +84,11 @@ func (r *ImageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl if an.CheckSum().IsNull() || !equal { if err := an.CheckSum().Set(image.Spec); err != nil { - log.Log.Error(err, "unable to refresh checksum") + xlog.WithError(err).Error("unable to set checksum") return ctrl.Result{}, err } if err := r.Client.Update(ctx, &image); err != nil { - log.Log.Error(err, "unable to update Image") + xlog.WithError(err).Error("unable to update Image") return ctrl.Result{}, err } } @@ -93,7 +97,7 @@ func (r *ImageReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl image.SetStatusTag(an.Tag().Get()) if err := r.Status().Update(ctx, &image); err != nil { - log.Log.Error(err, "unable to update Image status") + xlog.WithError(err).Error("unable to update Image status") return ctrl.Result{}, err } diff --git a/internal/controller/kimup_controller.go b/internal/controller/kimup_controller.go index fb48533..5b74e32 100644 --- a/internal/controller/kimup_controller.go +++ b/internal/controller/kimup_controller.go @@ -2,9 +2,9 @@ package controller import ( "context" - "fmt" "time" + "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" @@ -12,11 +12,11 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/predicate" "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" "github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" ) // KimupReconciler reconciles a Image object @@ -42,11 +42,16 @@ type KimupReconciler struct { // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { //nolint:gocyclo - log := log.FromContext(ctx) + xlog := log.WithContext(ctx).WithFields(logrus.Fields{ + "namespace": req.Namespace, + "name": req.Name, + }) var kim v1alpha1.Kimup if err := r.Get(ctx, req.NamespacedName, &kim); err != nil { - log.Info(fmt.Sprintf("cloud not get the Kimup object: %s", req.NamespacedName)) + if client.IgnoreNotFound(err) != nil { + xlog.WithError(err).Error("could not get the kimup object") + } return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -80,7 +85,7 @@ func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl resourcesToUpdate = append(resourcesToUpdate, resource) continue } - log.Error(err, "could not create the resource") + xlog.WithError(err).Error("could not create the resource") rescheduleAfter = true continue } @@ -88,7 +93,7 @@ func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl for _, resource := range resourcesToUpdate { if err := r.Update(ctx, resource.obj); err != nil { - log.Error(err, "could not update the resource") + xlog.WithError(err).Error("could not update the resource") rescheduleAfter = true continue } @@ -109,7 +114,13 @@ func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl case "Deployment": var deployment appsv1.Deployment if err := r.Get(ctx, client.ObjectKeyFromObject(resource.obj), &deployment); err != nil { - log.Error(err, "could not get the deployment") + xlog. + WithError(err). + WithFields(logrus.Fields{ + "namespace": deployment.Namespace, + "name": deployment.Name, + "kind": deployment.Kind, + }).Error("could not get the deployment") rescheduleAfter = true continue } @@ -122,7 +133,11 @@ func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl } if deployment.Status.Replicas != deployment.Status.ReadyReplicas { - log.Info(fmt.Sprintf("The %s deployment in namespace %s is not ready yet", deployment.Name, deployment.Namespace)) + xlog.WithFields(logrus.Fields{ + "namespace": deployment.Namespace, + "name": deployment.Name, + "kind": deployment.Kind, + }).Warn("The deployment is not ready yet") rescheduleAfter = true continue } else { @@ -132,13 +147,23 @@ func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl case KimupAdmissionControllerName: kim.Status.AdmissionController.State = StateReady } - log.Info(fmt.Sprintf("The %s deployment in namespace %s is ready", deployment.Name, deployment.Namespace)) + xlog.WithFields(logrus.Fields{ + "namespace": deployment.Namespace, + "name": deployment.Name, + "kind": deployment.Kind, + }).Info("The deployment is ready") } case "DaemonSet": var daemonset appsv1.DaemonSet if err := r.Get(ctx, client.ObjectKeyFromObject(resource.obj), &daemonset); err != nil { - log.Error(err, "could not get the daemonset") + xlog. + WithError(err). + WithFields(logrus.Fields{ + "namespace": daemonset.Namespace, + "name": daemonset.Name, + "kind": daemonset.Kind, + }).Error("could not get the daemonset") rescheduleAfter = true continue } @@ -151,7 +176,11 @@ func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl } if daemonset.Status.DesiredNumberScheduled != daemonset.Status.NumberReady { - log.Info("The daemonset is not ready yet") + xlog.WithFields(logrus.Fields{ + "namespace": daemonset.Namespace, + "name": daemonset.Name, + "kind": daemonset.Kind, + }).Warn("The daemonset is not ready yet") rescheduleAfter = true continue } else { @@ -161,33 +190,49 @@ func (r *KimupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl case KimupAdmissionControllerName: kim.Status.AdmissionController.State = StateReady } - log.Info(fmt.Sprintf("The %s daemonset in namespace %s is ready", daemonset.Name, daemonset.Namespace)) + xlog.WithFields(logrus.Fields{ + "namespace": daemonset.Namespace, + "name": daemonset.Name, + "kind": daemonset.Kind, + }).Info("The daemonset is ready") } case "Service": var service corev1.Service if err := r.Get(ctx, client.ObjectKeyFromObject(resource.obj), &service); err != nil { - log.Error(err, "could not get the service") + xlog. + WithError(err). + WithFields(logrus.Fields{ + "namespace": service.Namespace, + "name": service.Name, + "kind": service.Kind, + }).Error("could not get the service") rescheduleAfter = true continue } if service.Spec.Type == corev1.ServiceTypeLoadBalancer { if len(service.Status.LoadBalancer.Ingress) == 0 { - log.Info("The service is not ready yet") + xlog.WithFields(logrus.Fields{ + "namespace": service.Namespace, + "name": service.Name, + "kind": service.Kind, + }).Warn("The service is not ready yet") rescheduleAfter = true continue } } default: - log.Info(fmt.Sprintf("Unknown resource type: %s", resource.kind)) + xlog.WithFields(logrus.Fields{ + "kind": resource.kind, + }).Warn("Unknown resource type") } } // Update status if err := r.Status().Update(ctx, &kim); err != nil { - log.Error(err, "could not update the status of the kimup object") + xlog.WithError(err).Error("could not update the status of the kimup object") } if rescheduleAfter { diff --git a/internal/controller/resources_admission.go b/internal/controller/resources_admission.go index 3a9a5ff..754784d 100644 --- a/internal/controller/resources_admission.go +++ b/internal/controller/resources_admission.go @@ -201,7 +201,7 @@ func GetKimupAdmissionResources(ctx context.Context, ki v1alpha1.Kimup) []Object resources = append(resources, Object{kind: daemonset.TypeMeta.Kind, obj: &daemonset}) } // end switch - if ki.Spec.Controller.Healthz.Enabled || ki.Spec.Controller.Metrics.Enabled { + if ki.Spec.AdmissionController.Healthz.Enabled || ki.Spec.AdmissionController.Metrics.Enabled { service := corev1.Service{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", diff --git a/internal/kubeclient/client.go b/internal/kubeclient/client.go index 33ed46e..fbe11cb 100644 --- a/internal/kubeclient/client.go +++ b/internal/kubeclient/client.go @@ -7,7 +7,6 @@ import ( "fmt" "strings" - log "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -133,7 +132,6 @@ func (c *Client) GetPullSecretsForImage(ctx context.Context, image v1alpha1.Imag k = strings.TrimPrefix(k, i) } - log.Debugf("Found auth for %s", k) auths.Auths[k] = v } } diff --git a/internal/kubeclient/image.go b/internal/kubeclient/image.go index ac83819..bb8badc 100644 --- a/internal/kubeclient/image.go +++ b/internal/kubeclient/image.go @@ -4,13 +4,13 @@ import ( "context" "fmt" - log "github.com/sirupsen/logrus" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "github.com/orange-cloudavenue/kube-image-updater/api/v1alpha1" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" ) type ( @@ -152,7 +152,7 @@ func (i *ImageObj) Watch(ctx context.Context) (chan WatchInterface[v1alpha1.Imag image, err := decodeUnstructured[v1alpha1.Image](event.Object.(*unstructured.Unstructured)) if err != nil { - log.Errorf("Error decoding image: %v", err) + log.WithError(err).Error("Failed to decode image") continue } diff --git a/internal/log/log.go b/internal/log/log.go new file mode 100644 index 0000000..3145871 --- /dev/null +++ b/internal/log/log.go @@ -0,0 +1,160 @@ +package log + +import ( + "context" + "flag" + "fmt" + "os" + "time" + + "github.com/sirupsen/logrus" + "golang.org/x/term" +) + +const LogLevelFlagName = "loglevel" + +func init() { + flag.String( + LogLevelFlagName, + logrus.InfoLevel.String(), + fmt.Sprintf("Log level available: %s", logrus.AllLevels), + ) + + loglevel, err := logrus.ParseLevel(flag.Lookup(LogLevelFlagName).Value.String()) + if err != nil { + logrus.SetLevel(logrus.InfoLevel) + } else { + logrus.SetLevel(loglevel) + } + + // IsTerminal return true if the file descriptor is a terminal (TTY) + if term.IsTerminal(int(os.Stdout.Fd())) { + // Set the log format to text if the output is a terminal + logrus.SetFormatter(&logrus.TextFormatter{ + FullTimestamp: true, + }) + } else { + // Set the log format to JSON if the output is not a terminal (Daemon, Container...) + logrus.SetFormatter(&logrus.JSONFormatter{}) + } +} + +func GetLogger() *logrus.Logger { + return logrus.StandardLogger() +} + +func Info(args ...interface{}) { + logrus.Info(args...) +} + +func Infof(format string, args ...interface{}) { + logrus.Infof(format, args...) +} + +func Infoln(args ...interface{}) { + logrus.Infoln(args...) +} + +func Warn(args ...interface{}) { + logrus.Warn(args...) +} + +func Warnf(format string, args ...interface{}) { + logrus.Warnf(format, args...) +} + +func Warnln(args ...interface{}) { + logrus.Warnln(args...) +} + +func Error(args ...interface{}) { + logrus.Error(args...) +} + +func Errorf(format string, args ...interface{}) { + logrus.Errorf(format, args...) +} + +func Errorln(args ...interface{}) { + logrus.Errorln(args...) +} + +func Fatal(args ...interface{}) { + logrus.Fatal(args...) +} + +func Fatalf(format string, args ...interface{}) { + logrus.Fatalf(format, args...) +} + +func Fatalln(args ...interface{}) { + logrus.Fatalln(args...) +} + +func Panic(args ...interface{}) { + logrus.Panic(args...) +} + +func Panicf(format string, args ...interface{}) { + logrus.Panicf(format, args...) +} + +func Panicln(args ...interface{}) { + logrus.Panicln(args...) +} + +func Debug(args ...interface{}) { + logrus.Debug(args...) +} + +func Debugf(format string, args ...interface{}) { + logrus.Debugf(format, args...) +} + +func Debugln(args ...interface{}) { + logrus.Debugln(args...) +} + +func Print(args ...interface{}) { + logrus.Print(args...) +} + +func Printf(format string, args ...interface{}) { + logrus.Printf(format, args...) +} + +func Println(args ...interface{}) { + logrus.Println(args...) +} + +func Trace(args ...interface{}) { + logrus.Trace(args...) +} + +func Tracef(format string, args ...interface{}) { + logrus.Tracef(format, args...) +} + +func Traceln(args ...interface{}) { + logrus.Traceln(args...) +} + +func WithField(key string, value interface{}) *logrus.Entry { + return logrus.WithField(key, value) +} + +func WithFields(fields logrus.Fields) *logrus.Entry { + return logrus.WithFields(fields) +} + +func WithError(err error) *logrus.Entry { + return logrus.WithError(err) +} + +func WithContext(ctx context.Context) *logrus.Entry { + return logrus.WithContext(ctx) +} + +func WithTime(t time.Time) *logrus.Entry { + return logrus.WithTime(t) +} diff --git a/internal/models/log.go b/internal/models/log.go index b55e76d..44b3c1e 100644 --- a/internal/models/log.go +++ b/internal/models/log.go @@ -1,3 +1,5 @@ package models -var LogLevelFlagName = "loglevel" +import "github.com/orange-cloudavenue/kube-image-updater/internal/log" + +var LogLevelFlagName = log.LogLevelFlagName diff --git a/internal/rules/rules.go b/internal/rules/rules.go index 0fa65af..3db916a 100644 --- a/internal/rules/rules.go +++ b/internal/rules/rules.go @@ -1,8 +1,6 @@ package rules -import ( - log "github.com/sirupsen/logrus" -) +import "github.com/orange-cloudavenue/kube-image-updater/internal/log" type ( RuleInterface interface { @@ -33,7 +31,6 @@ const ( ) func register(name Name, rule RuleInterface) { - log.Infof("Registering rule %s", name) rules[name] = rule } diff --git a/internal/rules/semver.go b/internal/rules/semver.go index efc279b..7eed2d3 100644 --- a/internal/rules/semver.go +++ b/internal/rules/semver.go @@ -5,7 +5,8 @@ import ( "sort" "github.com/Masterminds/semver/v3" - log "github.com/sirupsen/logrus" + + "github.com/orange-cloudavenue/kube-image-updater/internal/log" ) var ( @@ -48,13 +49,13 @@ func (s *semverMajor) Evaluate() (matchWithRule bool, newTag string, err error) for _, t := range s.tags { ac, err := semver.NewVersion(t) if err != nil { - log.Errorf("Error parsing actual tag %s: %s", t, err) + log.WithError(err).WithField("tag", t).Error("Error parsing actual tag") continue } v, err := semver.NewConstraint(fmt.Sprintf("^%s", x.IncMajor())) if err != nil { - log.Errorf("Error parsing constraint %s: %s", x.IncMajor(), err) + log.WithError(err).WithField("constraint", x.IncMajor()).Error("Error parsing constraint") continue } @@ -81,13 +82,13 @@ func (s *semverMinor) Evaluate() (matchWithRule bool, newTag string, err error) for _, t := range s.tags { ac, err := semver.NewVersion(t) if err != nil { - log.Errorf("Error parsing available tag %s: %s", t, err) + log.WithError(err).WithField("tag", t).Error("Error parsing actual tag") continue } v, err := semver.NewConstraint(fmt.Sprintf("^%s", x.IncMinor())) if err != nil { - log.Errorf("Error parsing constraint %s: %s", x.IncMinor(), err) + log.WithError(err).WithField("constraint", x.IncMinor()).Error("Error parsing constraint") continue } @@ -114,13 +115,13 @@ func (s *semverPatch) Evaluate() (matchWithRule bool, newTag string, err error) for _, t := range s.tags { ac, err := semver.NewVersion(t) if err != nil { - log.Errorf("Error parsing actual tag %s: %s", t, err) + log.WithError(err).WithField("tag", t).Error("Error parsing actual tag") continue } v, err := semver.NewConstraint(fmt.Sprintf(">=%s <%s", x.IncPatch(), x.IncMinor())) if err != nil { - log.Errorf("Error parsing constraint %s: %s", x.IncPatch(), err) + log.WithError(err).WithField("constraint", x.IncPatch()).Error("Error parsing constraint") continue } diff --git a/internal/triggers/crontab/crontab.go b/internal/triggers/crontab/crontab.go index 8662b6c..2b2bcd1 100644 --- a/internal/triggers/crontab/crontab.go +++ b/internal/triggers/crontab/crontab.go @@ -5,8 +5,9 @@ import ( "github.com/reugn/go-quartz/job" "github.com/reugn/go-quartz/quartz" - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" + "github.com/orange-cloudavenue/kube-image-updater/internal/log" "github.com/orange-cloudavenue/kube-image-updater/internal/triggers" ) @@ -19,10 +20,19 @@ func New(ctx context.Context) { type CronTrigger struct{} func AddCronTab(namespace, name, crontab string) error { - log.Infof("Registering crontab (%s) for %s in namespace %s", crontab, name, namespace) + log.WithFields(logrus.Fields{ + "crontab": crontab, + "namespace": namespace, + "name": name, + }).Info("Registering crontab") + cronTrigger, _ := quartz.NewCronTrigger(crontab) functionJob := job.NewFunctionJob(func(_ context.Context) (string, error) { - log.Infof("[Fire] Crontab trigger refresh for image %s in namespace %s", name, namespace) + log.WithFields(logrus.Fields{ + "namespace": namespace, + "name": name, + }).Info("Crontab trigger refresh") + _, err := triggers.Trigger(triggers.RefreshImage, namespace, name) return "", err }) diff --git a/internal/triggers/triggers.go b/internal/triggers/triggers.go index e8967e9..0891320 100644 --- a/internal/triggers/triggers.go +++ b/internal/triggers/triggers.go @@ -2,7 +2,9 @@ package triggers import ( "github.com/gookit/event" - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" + + "github.com/orange-cloudavenue/kube-image-updater/internal/log" ) type ( @@ -23,7 +25,12 @@ func (e EventName) String() string { } func Trigger(e EventName, namespace, imageName string) (event.Event, error) { - log.Infof("Triggering event %s for image %s in namespace %s", e.String(), imageName, namespace) + log. + WithFields(logrus.Fields{ + "namespace": namespace, + "image": imageName, + }).Infof("Triggering event %s", e.String()) + event.Async(e.String(), event.M{"namespace": namespace, "image": imageName}) return nil, nil } diff --git a/internal/utils/log.go b/internal/utils/log.go index e5a6763..d4b585b 100644 --- a/internal/utils/log.go +++ b/internal/utils/log.go @@ -1,24 +1 @@ package utils - -import ( - log "github.com/sirupsen/logrus" -) - -func ParseLogLevel(logLevel string) log.Level { - switch logLevel { - case "debug": - return log.DebugLevel - case "info": - return log.InfoLevel - case "warn": - return log.WarnLevel - case "error": - return log.ErrorLevel - case "fatal": - return log.FatalLevel - case "panic": - return log.PanicLevel - default: - return log.InfoLevel - } -}