diff --git a/ci/obd-demo.yaml b/ci/obd-demo.yaml index efd4d10..aa4df3e 100644 --- a/ci/obd-demo.yaml +++ b/ci/obd-demo.yaml @@ -3,18 +3,15 @@ kind: Deployment metadata: name: cartservice-v1 labels: - app: cartservice - version: v1 + app.kubernetes.io/name: cartservice spec: selector: matchLabels: - app: cartservice - version: v1 + app.kubernetes.io/name: cartservice template: metadata: labels: - app: cartservice - version: v1 + app.kubernetes.io/name: cartservice spec: terminationGracePeriodSeconds: 5 containers: @@ -66,14 +63,13 @@ kind: Service metadata: name: cartservice labels: - app: cartservice - version: v1 + app.kubernetes.io/name: cartservice annotations: kardinal.dev.service/dependencies: "postgres:tcp" spec: type: ClusterIP selector: - app: cartservice + app.kubernetes.io/name: cartservice ports: - name: http port: 8090 @@ -86,18 +82,15 @@ kind: Deployment metadata: name: frontend-v1 labels: - app: frontend - version: v1 + app.kubernetes.io/name: frontend spec: selector: matchLabels: - app: frontend - version: v1 + app.kubernetes.io/name: frontend template: metadata: labels: - app: frontend - version: v1 + app.kubernetes.io/name: frontend annotations: sidecar.istio.io/rewriteAppHTTPProbers: "true" spec: @@ -139,20 +132,14 @@ kind: Service metadata: name: frontend labels: - app: frontend - version: v1 + app.kubernetes.io/name: frontend annotations: kardinal.dev.service/dependencies: "productcatalogservice:http,cartservice:http" - kardinal.dev.service/plugins: | - - name: https://github.com/kurtosis-tech/free-currency-api-plugin.git - type: external - servicename: free-currency-api - args: - api_key: fca_live_VKZlykCWEiFcpBHnw74pzd4vLi04q1h9JySbVHDF + kardinal.dev.service/plugins: "jsdelivr-api" spec: type: ClusterIP selector: - app: frontend + app.kubernetes.io/name: frontend ports: - name: http port: 80 @@ -166,19 +153,16 @@ kind: Deployment metadata: name: postgres-v1 labels: - app: postgres - version: v1 + app.kubernetes.io/name: postgres spec: replicas: 1 selector: matchLabels: - app: postgres - version: v1 + app.kubernetes.io/name: postgres template: metadata: labels: - app: postgres - version: v1 + app.kubernetes.io/name: postgres spec: containers: - name: postgres @@ -206,36 +190,10 @@ kind: Service metadata: name: postgres labels: - app: postgres - version: v1 + app.kubernetes.io/name: postgres annotations: kardinal.dev.service/stateful: "true" - kardinal.dev.service/plugins: | - - name: github.com/kurtosis-tech/postgres-seed-plugin - args: - seed_script: | - -- create the table - CREATE TABLE IF NOT EXISTS public.items( - id bigserial PRIMARY KEY, - created_at TIMESTAMP WITH TIME ZONE, - updated_at TIMESTAMP WITH TIME ZONE, - deleted_at TIMESTAMP WITH TIME ZONE, - user_id TEXT, - product_id TEXT, - quantity INTEGER - ); - - INSERT INTO public.items (id, created_at, updated_at, deleted_at, user_id, product_id, quantity) - VALUES (1, '2024-08-02 13:02:07.656104 +00:00', '2024-08-02 13:02:07.656104 +00:00', null, '0494c5e0-dde0-48fa-a6d8-f7962f5476bf', '66VCHSJNUP', 1); - - INSERT INTO public.items (id, created_at, updated_at, deleted_at, user_id, product_id, quantity) - VALUES (2, '2024-08-02 13:02:10.891407 +00:00', '2024-08-02 13:02:10.891407 +00:00', null, '0494c5e0-dde0-48fa-a6d8-f7962f5476bf', '2ZYFJ3GM2N', 1); - - -- Set the sequence to the correct value after inserting records - SELECT setval('public.items_id_seq', (SELECT MAX(id) FROM public.items)); - db_name: "cart" - db_user: "postgresuser" - db_password: "postgrespass" + kardinal.dev.service/plugins: "postgres-seed-plugin" spec: type: ClusterIP @@ -245,7 +203,7 @@ spec: targetPort: 5432 protocol: TCP selector: - app: postgres + app.kubernetes.io/name: postgres --- apiVersion: apps/v1 @@ -253,18 +211,15 @@ kind: Deployment metadata: name: productcatalogservice-v1 labels: - app: productcatalogservice - version: v1 + app.kubernetes.io/name: productcatalogservice spec: selector: matchLabels: - app: productcatalogservice - version: v1 + app.kubernetes.io/name: productcatalogservice template: metadata: labels: - app: productcatalogservice - version: v1 + app.kubernetes.io/name: productcatalogservice spec: terminationGracePeriodSeconds: 5 containers: @@ -299,12 +254,11 @@ kind: Service metadata: name: productcatalogservice labels: - app: productcatalogservice - version: v1 + app.kubernetes.io/name: productcatalogservice spec: type: ClusterIP selector: - app: productcatalogservice + app.kubernetes.io/name: productcatalogservice ports: - name: http port: 8070 diff --git a/kardinal/reconciler/reconciler.go b/kardinal/reconciler/reconciler.go index 17f1178..4e2a6e8 100644 --- a/kardinal/reconciler/reconciler.go +++ b/kardinal/reconciler/reconciler.go @@ -2,7 +2,6 @@ package reconciler import ( "context" - "github.com/brunoga/deep" "github.com/kurtosis-tech/stacktrace" "github.com/sirupsen/logrus" @@ -11,6 +10,20 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) +const ( + // Thi is a common label used in several applications and recommended by Kubernetes: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/ + appNameKubernetesLabelKey = "app.kubernetes.io/name" + appLabelKey = "app" + versionLabelKey = "version" + defaultVersionLabelValue = "baseline" +) + +type labeledResources interface { + GetLabels() map[string]string + SetLabels(labels map[string]string) + GetName() string +} + func Reconcile(ctx context.Context, cl client.Client) error { logrus.Info("Reconciling") @@ -20,6 +33,11 @@ func Reconcile(ctx context.Context, cl client.Client) error { if err != nil { return stacktrace.Propagate(err, "An error occurred retrieving the list of resources") } + + if err := reconcileIstioLabelsForBaselineServicesAndDeployments(ctx, cl, clusterResources); err != nil { + return stacktrace.Propagate(err, "An error occurred reconciling the Istio labels") + } + // Generate base cluster topology logrus.Info("Generate base cluster topology") baseClusterTopology, err := topology.NewClusterTopologyFromResources(clusterResources) @@ -95,3 +113,56 @@ func Reconcile(ctx context.Context, cl client.Client) error { return nil } + +// OPERATOR-TODO make sure to execute this again once we connect the operator to listen to k8s Deployments and Services events +// OPERATOR-TODO there is another approach we could take, if it doesn't works for all use cases, which is to use MutatingAdmissionWebHooks +// related info for this here: https://book.kubebuilder.io/cronjob-tutorial/webhook-implementation and particularly this https://book.kubebuilder.io/reference/webhook-for-core-types +// for creating and webhook for these core types. +func reconcileIstioLabelsForBaselineServicesAndDeployments(ctx context.Context, cl client.Client, clusterResources *resources.Resources) error { + for _, namespace := range clusterResources.Namespaces { + for _, service := range namespace.Services { + ensureIstioLabelsForResource(service) + if err := cl.Update(ctx, service); err != nil { + return stacktrace.Propagate(err, "An error occurred adding Istio labels to service '%s'", service.GetName()) + } + } + + for _, deployment := range namespace.Deployments { + ensureIstioLabelsForResource(deployment) + if err := cl.Update(ctx, deployment); err != nil { + return stacktrace.Propagate(err, "An error occurred adding Istio labels to deployment '%s'", deployment.GetName()) + } + } + } + return nil +} + +func ensureIstioLabelsForResource(resource labeledResources) error { + + labels := resource.GetLabels() + if labels == nil { + labels = map[string]string{} + } + + // The 'app' label + _, ok := labels[appLabelKey] + if !ok { + appNameKubernetesLabelValue, ok := labels[appNameKubernetesLabelKey] + if ok { + labels[appLabelKey] = appNameKubernetesLabelValue + } else { + labels[appLabelKey] = resource.GetName() + } + } + + // The 'version' label + // OPERATOR-TODO how are we going to handle when a non-managed resource already has the "version" label and + // this value is different from the value needed for managing the baseline traffic + _, ok = labels[versionLabelKey] + if !ok { + labels[versionLabelKey] = defaultVersionLabelValue + } + resource.SetLabels(labels) + + return nil +} diff --git a/kardinal/resources/resources.go b/kardinal/resources/resources.go index 1b56d7f..30fc647 100644 --- a/kardinal/resources/resources.go +++ b/kardinal/resources/resources.go @@ -176,8 +176,6 @@ func ApplyServiceResources(ctx context.Context, clusterResources *Resources, clu } } } - // OPERATOR-TODO: Set app and version labels on non-managed service if not already set. - // Those labels are required by Istio. } } }