Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: enhancement metrics method #48

Merged
merged 3 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions cmd/admission-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,21 @@ import (
"syscall"
"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

webhookNamespace string = "example.com"
webhookServiceName string = "your"
webhookConfigName string = "webhookconfig"
webhookNamespace string = "nip.io"
webhookServiceName string = "192-168-1-23"
webhookConfigName string = "mutating-webhook-configuration"
webhookPathMutate string = "/mutate"
webhookPort string = ":8443"
webhookBase = webhookServiceName + "." + webhookNamespace
Expand All @@ -36,13 +34,7 @@ var (
deserializer = codecs.UniversalDeserializer()

kubeClient client.Interface
manifestWebhookPath string = "./config/manifests/mutatingWebhookConfiguration.yaml"

// Prometheus metrics
promHTTPRequestsTotal prometheus.Counter = metrics.NewCounter("http_requests_total", "The total number of handled HTTP requests.")
promHTTPErrorsTotal prometheus.Counter = metrics.NewCounter("http_errors_total", "The total number of handled HTTP errors.")
promHTTPDuration prometheus.Histogram = metrics.NewHistogram("http_response_time_seconds", "The duration in seconds of HTTP requests.")
promPatchTotal prometheus.Counter = metrics.NewCounter("patch_total", "The total number of requests to a patch.")
manifestWebhookPath string = "./examples/mutatingWebhookConfiguration.yaml"
dmicheneau marked this conversation as resolved.
Show resolved Hide resolved
)

func init() {
Expand Down Expand Up @@ -98,7 +90,7 @@ func main() {
// * Config the webhook server
a, waitHTTP := httpserver.Init(ctx, httpserver.WithCustomHandlerForHealth(
func() (bool, error) {
_, err := net.DialTimeout("tcp", ":4444", 5*time.Second)
_, err := net.DialTimeout("tcp", webhookPort, 5*time.Second)
if err != nil {
return false, err
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/admission-controller/webhook-configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func createOrUpdateMutatingWebhookConfiguration(caPEM *bytes.Buffer, webhookServ
Name: webhookConfigName,
},
Webhooks: []admissionregistrationv1.MutatingWebhook{{
Name: webhookService + "." + webhookNamespace + ".svc",
Name: webhookService + "." + webhookNamespace,
AdmissionReviewVersions: []string{"v1", "v1beta1"},
SideEffects: &sideEffect,
ClientConfig: clientConfig,
Expand All @@ -58,11 +58,14 @@ func createOrUpdateMutatingWebhookConfiguration(caPEM *bytes.Buffer, webhookServ
{
Operations: []admissionregistrationv1.OperationType{
admissionregistrationv1.Update,
admissionregistrationv1.Create,
},
Rule: admissionregistrationv1.Rule{
APIGroups: []string{""},
APIVersions: []string{"v1"},
Resources: []string{"pods"},
// TODO - add namespace scope
// Scope: "*",
},
},
},
Expand Down
47 changes: 34 additions & 13 deletions cmd/admission-controller/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"io"
"net/http"

"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
Expand All @@ -16,16 +15,16 @@ import (
"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/metrics"
"github.com/orange-cloudavenue/kube-image-updater/internal/patch"
)

// func serveHandler
func ServeHandler(w http.ResponseWriter, r *http.Request) {
// start the timer
timer := prometheus.NewTimer(promHTTPDuration)
defer timer.ObserveDuration()
// increment the totalRequests counter
promHTTPRequestsTotal.Inc()
// Prometheus metrics
metrics.AdmissionController().Total().Inc()
timeAC := metrics.AdmissionController().Duration()
defer timeAC.ObserveDuration()

var body []byte
if r.Body != nil {
Expand All @@ -34,7 +33,9 @@ func ServeHandler(w http.ResponseWriter, r *http.Request) {
}
}
if len(body) == 0 {
promHTTPErrorsTotal.Inc()
// increment the total number of errors
metrics.AdmissionController().TotalErr().Inc()

log.Error("empty body")
http.Error(w, "empty body", http.StatusBadRequest)
return
Expand All @@ -43,15 +44,19 @@ func ServeHandler(w http.ResponseWriter, r *http.Request) {
// verify the content type is accurate
contentType := r.Header.Get("Content-Type")
if contentType != "application/json" {
promHTTPErrorsTotal.Inc()
// increment the total number of errors
metrics.AdmissionController().TotalErr().Inc()

http.Error(w, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
return
}

var admissionResponse *admissionv1.AdmissionResponse
ar := admissionv1.AdmissionReview{}
if _, _, err := deserializer.Decode(body, nil, &ar); err != nil {
promHTTPErrorsTotal.Inc()
// increment the total number of errors
metrics.AdmissionController().TotalErr().Inc()

log.WithError(err).Warn("Can't decode body")
admissionResponse = &admissionv1.AdmissionResponse{
Result: &metav1.Status{
Expand All @@ -77,11 +82,15 @@ func ServeHandler(w http.ResponseWriter, r *http.Request) {

resp, err := json.Marshal(admissionReview)
if err != nil {
promHTTPErrorsTotal.Inc()
// increment the total number of errors
metrics.AdmissionController().TotalErr().Inc()

http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
}
if _, err := w.Write(resp); err != nil {
promHTTPErrorsTotal.Inc()
// increment the total number of errors
metrics.AdmissionController().TotalErr().Inc()

http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
}
}
Expand Down Expand Up @@ -128,10 +137,18 @@ func mutate(ctx context.Context, ar *admissionv1.AdmissionReview) *admissionv1.A

// create mutation patch for pod.
func createPatch(ctx context.Context, pod *corev1.Pod) ([]byte, error) {
// Metrics - increment the total number of patch
metrics.AdmissionControllerPatch().Total().Inc()
dmicheneau marked this conversation as resolved.
Show resolved Hide resolved
timePatch := metrics.AdmissionControllerPatch().Duration()
defer timePatch.ObserveDuration()

var err error
// find annotation enabled
an := annotations.New(ctx, pod)
if !an.Enabled().Get() {
// increment the total number of errors
metrics.AdmissionControllerPatch().TotalErr().Inc()

return nil, fmt.Errorf("annotation not enabled")
}

Expand All @@ -154,6 +171,9 @@ 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 {
// increment the total number of errors
metrics.AdmissionControllerPatch().TotalErr().Inc()

log.
WithFields(logrus.Fields{
"Namespace": pod.Namespace,
Expand All @@ -166,6 +186,9 @@ func createPatch(ctx context.Context, pod *corev1.Pod) ([]byte, error) {
} else {
image, err = kubeClient.Image().Get(ctx, pod.Namespace, crdName)
if err != nil {
// increment the total number of errors
metrics.AdmissionControllerPatch().TotalErr().Inc()

log.
WithFields(logrus.Fields{
"Namespace": pod.Namespace,
Expand All @@ -179,8 +202,6 @@ func createPatch(ctx context.Context, pod *corev1.Pod) ([]byte, error) {
// Set the image to the pod
if image.ImageIsEqual(container.Image) {
p.AddPatch(patch.OpReplace, fmt.Sprintf("/spec/containers/%d/image", i), image.GetImageWithTag())
// increment the total number of patches
promPatchTotal.Inc()
}

// Annotations
Expand Down
59 changes: 52 additions & 7 deletions cmd/kimup/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/orange-cloudavenue/kube-image-updater/internal/actions"
"github.com/orange-cloudavenue/kube-image-updater/internal/kubeclient"
"github.com/orange-cloudavenue/kube-image-updater/internal/metrics"
"github.com/orange-cloudavenue/kube-image-updater/internal/models"
"github.com/orange-cloudavenue/kube-image-updater/internal/registry"
"github.com/orange-cloudavenue/kube-image-updater/internal/rules"
Expand All @@ -28,6 +29,12 @@ func initScheduler(ctx context.Context, k kubeclient.Interface) {
crontab.New(ctx)
// Add event lock
event.On(triggers.RefreshImage.String(), event.ListenerFunc(func(e event.Event) (err error) {
// Increment the counter for the events
metrics.Events().Total().Inc()
// Start the timer for the event execution
timerEvents := metrics.Events().Duration()
defer timerEvents.ObserveDuration()

if l[e.Data()["namespace"].(string)+"/"+e.Data()["image"].(string)] == nil {
l[e.Data()["namespace"].(string)+"/"+e.Data()["image"].(string)] = &sync.RWMutex{}
}
Expand Down Expand Up @@ -64,6 +71,10 @@ func initScheduler(ctx context.Context, k kubeclient.Interface) {

i := utils.ImageParser(image.Spec.Image)

// Prometheus metrics - Increment the counter for the registry
metrics.Registry().Total().Inc()
timerRegistry := metrics.Registry().Duration()

re, err := registry.New(ctx, image.Spec.Image, registry.Settings{
InsecureTLS: image.Spec.InsecureSkipTLSVerify,
Username: func() string {
Expand All @@ -79,12 +90,24 @@ func initScheduler(ctx context.Context, k kubeclient.Interface) {
return ""
}(),
})
timerRegistry.ObserveDuration()
if err != nil {
// Prometheus metrics - Increment the counter for the registry with error
metrics.Registry().TotalErr().Inc()

return err
}

// Prometheus metrics - Increment the counter for the tags
metrics.Tags().Total().Inc()
timerTags := metrics.Tags().Duration()

tagsAvailable, err := re.Tags()
timerTags.ObserveDuration()
if err != nil {
// Prometheus metrics - Increment the counter for the tags with error
metrics.Tags().TotalErr().Inc()

return err
}

Expand All @@ -103,8 +126,20 @@ func initScheduler(ctx context.Context, k kubeclient.Interface) {
}

r.Init(tag, tagsAvailable, rule.Value)

// Prometheus metrics - Increment the counter for the rules
metrics.Rules().Total().Inc()
timerRules := metrics.Rules().Duration()

match, newTag, err := r.Evaluate()

// Prometheus metrics - Observe the duration of the rule evaluation
timerRules.ObserveDuration()

if err != nil {
// Prometheus metrics - Increment the counter for the evaluated rule with error
metrics.Rules().TotalErr().Inc()

log.Errorf("Error evaluating rule: %v", err)
continue
}
Expand All @@ -122,23 +157,33 @@ func initScheduler(ctx context.Context, k kubeclient.Interface) {
New: newTag,
AvailableTags: tagsAvailable,
}, &image, action.Data)
if err := a.Execute(ctx); err != nil {

// Prometheus metrics - Increment the counter for the actions
metrics.Actions().Total().Inc()
timerActions := metrics.Actions().Duration()

err = a.Execute(ctx)

// Prometheus metrics - Observe the duration of the action execution
timerActions.ObserveDuration()

if err != nil {
// Prometheus metrics - Increment the counter for the executed action with error
metrics.Actions().TotalErr().Inc()

log.Errorf("Error executing action(%s): %v", action.Type, err)
continue
}
}

log.Debugf("[RefreshImage] Rule %s evaluated: %v -> %s", rule.Type, tag, newTag)
}
}

if err := k.Image().Update(ctx, image); err != nil {
return err
}

return nil
return k.Image().Update(ctx, image)
})

// Prometheus metrics - Increment the counter for the events evaluated with error
metrics.Events().TotalErr().Inc()
return retryErr
}), event.Normal)
}
6 changes: 2 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ require (
github.com/go-chi/chi/v5 v5.1.0
github.com/gookit/event v1.1.2
github.com/onsi/ginkgo/v2 v2.20.2
github.com/onsi/gomega v1.34.2
github.com/prometheus/client_golang v1.20.4
github.com/reugn/go-quartz v0.13.0
github.com/sirupsen/logrus v1.9.3
Expand Down Expand Up @@ -48,7 +47,6 @@ require (
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/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
Expand All @@ -66,6 +64,7 @@ require (
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
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
Expand All @@ -74,6 +73,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/gomega v1.34.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect
Expand All @@ -86,8 +86,6 @@ require (
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.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
Expand Down
2 changes: 1 addition & 1 deletion internal/httpserver/httpserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func init() {
// * Metrics
flag.Bool(models.MetricsFlagName, false, "Enable the metrics server.")
flag.StringVar(&metricsPort, models.MetricsPortFlagName, models.MetricsDefaultAddr, "Metrics server port.")
flag.StringVar(&metricsPath, models.MetricsPathFlagName, models.HealthzDefaultPath, "Metrics server path.")
flag.StringVar(&metricsPath, models.MetricsPathFlagName, models.MetricsDefaultPath, "Metrics server path.")
}

// Function to initialize application, return app struct and a func waitgroup.
Expand Down
Loading