From f69e42d7baa4e987f3dcf7a6c0d7b7347bf67e1a Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 30 May 2024 13:31:25 -0400 Subject: [PATCH] feat: adding labels to all resources mutated by the agent (#2557) ## Description Adds labels to any resource mutated by the agent ## Checklist before merging - [ ] Test, docs, adr added or updated as needed - [ ] [Contributor Guide Steps](https://github.com/defenseunicorns/zarf/blob/main/.github/CONTRIBUTING.md#developer-workflow) followed --- .../agent/hooks/argocd-application.go | 4 ++++ .../agent/hooks/argocd-application_test.go | 6 +++++ src/internal/agent/hooks/argocd-repository.go | 5 +++- .../agent/hooks/argocd-repository_test.go | 14 +++++++++++ src/internal/agent/hooks/common.go | 15 ++++++++++++ src/internal/agent/hooks/flux.go | 1 + src/internal/agent/hooks/flux_test.go | 12 ++++++++++ src/internal/agent/hooks/pods.go | 23 ++++++------------- src/internal/agent/hooks/pods_test.go | 12 ++++++---- 9 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 src/internal/agent/hooks/common.go diff --git a/src/internal/agent/hooks/argocd-application.go b/src/internal/agent/hooks/argocd-application.go index 90a5b98744..0e037fbb00 100644 --- a/src/internal/agent/hooks/argocd-application.go +++ b/src/internal/agent/hooks/argocd-application.go @@ -17,6 +17,7 @@ import ( "github.com/defenseunicorns/zarf/src/pkg/transform" "github.com/defenseunicorns/zarf/src/types" v1 "k8s.io/api/admission/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // Application is a definition of an ArgoCD Application resource. @@ -29,6 +30,7 @@ import ( // For more information: https://argo-cd.readthedocs.io/en/stable/user-guide/import/ type Application struct { Spec ApplicationSpec `json:"spec"` + metav1.ObjectMeta } // ApplicationSpec represents desired application state. Contains link to repository with application definition. @@ -93,6 +95,8 @@ func mutateApplication(ctx context.Context, r *v1.AdmissionRequest, cluster *clu } } + patches = append(patches, getLabelPatch(app.Labels)) + return &operations.Result{ Allowed: true, PatchOps: patches, diff --git a/src/internal/agent/hooks/argocd-application_test.go b/src/internal/agent/hooks/argocd-application_test.go index 5d241dd571..6ef39b2730 100644 --- a/src/internal/agent/hooks/argocd-application_test.go +++ b/src/internal/agent/hooks/argocd-application_test.go @@ -69,6 +69,12 @@ func TestArgoAppWebhook(t *testing.T) { "/spec/sources/1/repoURL", "https://git-server.com/a-push-user/almonds-640159520", ), + operations.ReplacePatchOperation( + "/metadata/labels", + map[string]string{ + "zarf-agent": "patched", + }, + ), }, code: http.StatusOK, }, diff --git a/src/internal/agent/hooks/argocd-repository.go b/src/internal/agent/hooks/argocd-repository.go index 9e643414d7..53d96af44b 100644 --- a/src/internal/agent/hooks/argocd-repository.go +++ b/src/internal/agent/hooks/argocd-repository.go @@ -95,9 +95,12 @@ func mutateRepositorySecret(ctx context.Context, r *v1.AdmissionRequest, cluster message.Debugf("original url of (%s) got mutated to (%s)", repoCreds.URL, patchedURL) } + patches := populateArgoRepositoryPatchOperations(patchedURL, state.GitServer) + patches = append(patches, getLabelPatch(secret.Labels)) + return &operations.Result{ Allowed: true, - PatchOps: populateArgoRepositoryPatchOperations(patchedURL, state.GitServer), + PatchOps: patches, }, nil } diff --git a/src/internal/agent/hooks/argocd-repository_test.go b/src/internal/agent/hooks/argocd-repository_test.go index b84a3e8d07..4506b682e1 100644 --- a/src/internal/agent/hooks/argocd-repository_test.go +++ b/src/internal/agent/hooks/argocd-repository_test.go @@ -73,6 +73,13 @@ func TestArgoRepoWebhook(t *testing.T) { "/data/password", b64.StdEncoding.EncodeToString([]byte(state.GitServer.PullPassword)), ), + operations.ReplacePatchOperation( + "/metadata/labels", + map[string]string{ + "argocd.argoproj.io/secret-type": "repository", + "zarf-agent": "patched", + }, + ), }, code: http.StatusOK, }, @@ -103,6 +110,13 @@ func TestArgoRepoWebhook(t *testing.T) { "/data/password", b64.StdEncoding.EncodeToString([]byte(state.GitServer.PullPassword)), ), + operations.ReplacePatchOperation( + "/metadata/labels", + map[string]string{ + "argocd.argoproj.io/secret-type": "repository", + "zarf-agent": "patched", + }, + ), }, code: http.StatusOK, }, diff --git a/src/internal/agent/hooks/common.go b/src/internal/agent/hooks/common.go new file mode 100644 index 0000000000..ed1de69797 --- /dev/null +++ b/src/internal/agent/hooks/common.go @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package hooks contains the mutation hooks for the Zarf agent. +package hooks + +import "github.com/defenseunicorns/zarf/src/internal/agent/operations" + +func getLabelPatch(currLabels map[string]string) operations.PatchOperation { + if currLabels == nil { + currLabels = make(map[string]string) + } + currLabels["zarf-agent"] = "patched" + return operations.ReplacePatchOperation("/metadata/labels", currLabels) +} diff --git a/src/internal/agent/hooks/flux.go b/src/internal/agent/hooks/flux.go index 617b91901c..77382aecf3 100644 --- a/src/internal/agent/hooks/flux.go +++ b/src/internal/agent/hooks/flux.go @@ -85,6 +85,7 @@ func mutateGitRepo(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster // Patch updates of the repo spec patches = populatePatchOperations(patchedURL) + patches = append(patches, getLabelPatch(repo.Labels)) return &operations.Result{ Allowed: true, diff --git a/src/internal/agent/hooks/flux_test.go b/src/internal/agent/hooks/flux_test.go index cf56ac844a..a68cbfe591 100644 --- a/src/internal/agent/hooks/flux_test.go +++ b/src/internal/agent/hooks/flux_test.go @@ -64,6 +64,12 @@ func TestFluxMutationWebhook(t *testing.T) { "/spec/secretRef", fluxmeta.LocalObjectReference{Name: config.ZarfGitServerSecretName}, ), + operations.ReplacePatchOperation( + "/metadata/labels", + map[string]string{ + "zarf-agent": "patched", + }, + ), }, code: http.StatusOK, }, @@ -100,6 +106,12 @@ func TestFluxMutationWebhook(t *testing.T) { "/spec/secretRef", fluxmeta.LocalObjectReference{Name: config.ZarfGitServerSecretName}, ), + operations.ReplacePatchOperation( + "/metadata/labels", + map[string]string{ + "zarf-agent": "patched", + }, + ), }, code: http.StatusOK, }, diff --git a/src/internal/agent/hooks/pods.go b/src/internal/agent/hooks/pods.go index 658c585b12..299b841f31 100644 --- a/src/internal/agent/hooks/pods.go +++ b/src/internal/agent/hooks/pods.go @@ -64,11 +64,11 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu } registryURL := state.RegistryInfo.Address - var patchOperations []operations.PatchOperation + var patches []operations.PatchOperation // Add the zarf secret to the podspec zarfSecret := []corev1.LocalObjectReference{{Name: config.ZarfImagePullSecretName}} - patchOperations = append(patchOperations, operations.ReplacePatchOperation("/spec/imagePullSecrets", zarfSecret)) + patches = append(patches, operations.ReplacePatchOperation("/spec/imagePullSecrets", zarfSecret)) // update the image host for each init container for idx, container := range pod.Spec.InitContainers { @@ -78,7 +78,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu message.Warnf(lang.AgentErrImageSwap, container.Image) continue // Continue, because we might as well attempt to mutate the other containers for this pod } - patchOperations = append(patchOperations, operations.ReplacePatchOperation(path, replacement)) + patches = append(patches, operations.ReplacePatchOperation(path, replacement)) } // update the image host for each ephemeral container @@ -89,7 +89,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu message.Warnf(lang.AgentErrImageSwap, container.Image) continue // Continue, because we might as well attempt to mutate the other containers for this pod } - patchOperations = append(patchOperations, operations.ReplacePatchOperation(path, replacement)) + patches = append(patches, operations.ReplacePatchOperation(path, replacement)) } // update the image host for each normal container @@ -100,22 +100,13 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu message.Warnf(lang.AgentErrImageSwap, container.Image) continue // Continue, because we might as well attempt to mutate the other containers for this pod } - patchOperations = append(patchOperations, operations.ReplacePatchOperation(path, replacement)) + patches = append(patches, operations.ReplacePatchOperation(path, replacement)) } - // Add a label noting the zarf mutation - if pod.Labels == nil { - // If the labels path does not exist - create with map[string]string value - patchOperations = append(patchOperations, operations.AddPatchOperation("/metadata/labels", - map[string]string{ - "zarf-agent": "patched", - })) - } else { - patchOperations = append(patchOperations, operations.ReplacePatchOperation("/metadata/labels/zarf-agent", "patched")) - } + patches = append(patches, getLabelPatch(pod.Labels)) return &operations.Result{ Allowed: true, - PatchOps: patchOperations, + PatchOps: patches, }, nil } diff --git a/src/internal/agent/hooks/pods_test.go b/src/internal/agent/hooks/pods_test.go index 8eca704f59..3a41f9227c 100644 --- a/src/internal/agent/hooks/pods_test.go +++ b/src/internal/agent/hooks/pods_test.go @@ -46,7 +46,8 @@ func TestPodMutationWebhook(t *testing.T) { name: "pod with label should be mutated", admissionReq: createPodAdmissionRequest(t, v1.Create, &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"should-be": "mutated"}, + Labels: map[string]string{"should-be": "mutated"}, + Annotations: map[string]string{"should-be": "mutated"}, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{{Image: "nginx"}}, @@ -78,8 +79,11 @@ func TestPodMutationWebhook(t *testing.T) { "127.0.0.1:31999/library/nginx:latest-zarf-3793515731", ), operations.ReplacePatchOperation( - "/metadata/labels/zarf-agent", - "patched", + "/metadata/labels", + map[string]string{ + "zarf-agent": "patched", + "should-be": "mutated", + }, ), }, code: http.StatusOK, @@ -116,7 +120,7 @@ func TestPodMutationWebhook(t *testing.T) { "/spec/containers/0/image", "127.0.0.1:31999/library/nginx:latest-zarf-3793515731", ), - operations.AddPatchOperation( + operations.ReplacePatchOperation( "/metadata/labels", map[string]string{"zarf-agent": "patched"}, ),