From 1e0d79f0cab7b561624e12f5ffb31cca629ae12e Mon Sep 17 00:00:00 2001 From: Tchoupinax Date: Thu, 11 Apr 2024 13:52:29 +0200 Subject: [PATCH 1/3] feat: fix the matchselector issue and some little typos --- README.md | 8 ++++++++ logs.go | 1 + main.go | 6 +++--- steps.go | 26 +++++++++++++++----------- summary.go | 4 ++-- version.go | 4 ++-- 6 files changed, 31 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index ad8c3f9..a133fe9 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,14 @@ kubernetes-labels-migrator \ ![Screenshot of a terminal with all the execution](.github/docs/demo.png "CLI demo") +## Tutorial + +Let's say you are managing your application with the gitops's philosohpy ([ArgoCD](https://argo-cd.readthedocs.io/en/stable/) is really great to do the job). You want to add or edit a label. This difference has already been done by your code but ArgoCD refused to sync because of the "immutable field" error. Then following this: +- ⚠️ First of all, nothing intervene during the operation! `kubernetes-labels-migrator` should be free until the end. If you have tools like ArgoCD that synchronize your resources, **please** ensure this feature is **disabled**. +- You can commit the changes on the resource and observe the difference +- Launch the script and watch the magic happens +- According your changes, the difference should have been resolved + ## Motivation Deployment's labels are immutable. That means, if you have to edit, rename or add labels to a deployed application, you have to delete the deployment. On a production application, it is very annoying. diff --git a/logs.go b/logs.go index 36ee4cf..e1d6a88 100644 --- a/logs.go +++ b/logs.go @@ -20,6 +20,7 @@ func logBlocking(msg string) { magenta := color.New(color.Bold, color.FgHiMagenta).SprintFunc() fmt.Println(magenta(fmt.Sprintf("⌛️ %s", msg))) } + func logBlockingDot() { magenta := color.New(color.Bold, color.FgHiMagenta).SprintFunc() fmt.Print(magenta(".")) diff --git a/main.go b/main.go index 42261dd..f9c55f4 100644 --- a/main.go +++ b/main.go @@ -28,8 +28,8 @@ func main() { var labelToChangeValue = "" var goalOfOperationIsToRemoveLabel = false - flag.StringVar(&deploymentName, "deployment", "" , "Name of the deployment to edit label") - flag.StringVar(&namespace, "namespace", "" , "Namespace of the deployment to edit label") + flag.StringVar(&deploymentName, "deployment", "", "Name of the deployment to edit label") + flag.StringVar(&namespace, "namespace", "", "Namespace of the deployment to edit label") flag.BoolVar(&goalOfOperationIsToRemoveLabel, "remove-label", false, "If true, the label will be removed instead of be added/edited") flag.StringVar(&labelToChangeKey, "label", "app.kubernetes.io/name", "Name of the label") flag.StringVar(&labelToChangeValue, "value", "", "Value of the label") @@ -62,7 +62,7 @@ func main() { os.Exit(0) } - Step1( + MigrationWorkflow( namespace, clientset, deploymentName, diff --git a/steps.go b/steps.go index 6008671..a5f94fd 100644 --- a/steps.go +++ b/steps.go @@ -11,7 +11,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func Step1( +func MigrationWorkflow( namespace string, clientset *kubernetes.Clientset, deploymentName string, @@ -33,7 +33,7 @@ func Step1( // It's required because an error is thrown, we can not create a deployment with this property provided temporalDeployment.ResourceVersion = "" - _, err = clientset.AppsV1().Deployments(namespace).Create(context.TODO(), &temporalDeployment, metav1.CreateOptions{}); + _, err = clientset.AppsV1().Deployments(namespace).Create(context.TODO(), &temporalDeployment, metav1.CreateOptions{}) if err != nil { if strings.Contains(err.Error(), "already exists, the server was not able to generate a unique name for the object") { logWarning("1. Temporary deployment already created. Continue...") @@ -45,7 +45,7 @@ func Step1( logInfo("2. Updating the service...") var temporalService = *currentService delete(temporalService.Spec.Selector, changingLabelKey) - _, err = clientset.CoreV1().Services(namespace).Update(context.TODO(), &temporalService, metav1.UpdateOptions{}); + _, err = clientset.CoreV1().Services(namespace).Update(context.TODO(), &temporalService, metav1.UpdateOptions{}) check(err) logSuccess("2. Service updated") @@ -54,9 +54,9 @@ func Step1( for !areAllPodReady { logBlockingDot() time.Sleep(1 * time.Second) - areAllPodReady = - waitUntilAllPodAreReady(clientset, namespace, "api") && - waitUntilAllPodAreReady(clientset, namespace, fmt.Sprintf("%s-%s", currentDeployment.Name, "changing-label-tmp")) + areAllPodReady = + waitUntilAllPodAreReady(clientset, namespace, currentDeployment.Name) && + waitUntilAllPodAreReady(clientset, namespace, fmt.Sprintf("%s-%s", currentDeployment.Name, "changing-label-tmp")) } fmt.Println("") @@ -78,12 +78,17 @@ func Step1( if removeLabel { delete(futureOfficialDeployment.ObjectMeta.Labels, changingLabelKey) delete(futureOfficialDeployment.Spec.Template.ObjectMeta.Labels, changingLabelKey) - } else { + delete(futureOfficialDeployment.Spec.Selector.MatchLabels, changingLabelKey) + } else { + // Label of the deployment futureOfficialDeployment.ObjectMeta.Labels[changingLabelKey] = changingLabelValue + // Label of the pod created by the deployment futureOfficialDeployment.Spec.Template.ObjectMeta.Labels[changingLabelKey] = changingLabelValue + // Then we must include the label in the matchSelector for the deployment to find pods + futureOfficialDeployment.Spec.Selector.MatchLabels[changingLabelKey] = changingLabelValue } - _, err = clientset.AppsV1().Deployments(namespace).Create(context.TODO(), &futureOfficialDeployment, metav1.CreateOptions{}); + _, err = clientset.AppsV1().Deployments(namespace).Create(context.TODO(), &futureOfficialDeployment, metav1.CreateOptions{}) if err != nil { if strings.Contains(err.Error(), "already exists, the server was not able to generate a unique name for the object") { fmt.Println("⚠️ Temporary deployment already created. Continue...") @@ -97,7 +102,7 @@ func Step1( for !areAllPodReady { logBlockingDot() time.Sleep(1 * time.Second) - areAllPodReady = waitUntilAllPodAreReady(clientset, namespace, "api") + areAllPodReady = waitUntilAllPodAreReady(clientset, namespace, currentDeployment.Name) } fmt.Println("") @@ -109,7 +114,7 @@ func Step1( logSuccess("7. Temporary deployment deleted") } -func AddLabelToServiceSelector ( +func AddLabelToServiceSelector( namespace string, clientset *kubernetes.Clientset, applicationName string, @@ -123,7 +128,6 @@ func AddLabelToServiceSelector ( currentService, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), applicationName, metav1.GetOptions{}) check(err) - var futureService = *currentService if removeLabel { // Update the value of the label diff --git a/summary.go b/summary.go index 163c566..56359c1 100644 --- a/summary.go +++ b/summary.go @@ -18,8 +18,8 @@ func displaySummary( t := table.NewWriter() t.SetOutputMirror(os.Stdout) t.AppendHeader(table.Row{"Parameter", "Value"}) - t.AppendRows([]table.Row{{"Deployement name", namespace}}) - t.AppendRows([]table.Row{{"Namespace", deploymentName}}) + t.AppendRows([]table.Row{{"Deployment name", deploymentName}}) + t.AppendRows([]table.Row{{"Namespace", namespace}}) if goalOfOperationIsToRemoveLabel { t.AppendRows([]table.Row{{"Label", labelToChangeKey}}) } else { diff --git a/version.go b/version.go index c029abd..bc26e07 100644 --- a/version.go +++ b/version.go @@ -7,8 +7,8 @@ import ( "github.com/fatih/color" ) -const Version string = "0.1.1" -const BuildDate string = "2024-03-24" +const Version string = "0.1.2" +const BuildDate string = "2024-04-11" func cliCommandDisplayHelp(args []string) { displayVersion := stringInSlice("-v", args[1:]) || stringInSlice("--version", args[1:]) From 9e135512a6f880de7d4da8a06d2666b6809a0fdc Mon Sep 17 00:00:00 2001 From: Tchoupinax Date: Thu, 11 Apr 2024 14:22:49 +0200 Subject: [PATCH 2/3] fix: lint --- justfile | 5 ++++- utils.go | 10 ---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/justfile b/justfile index c4e862e..30eeccb 100644 --- a/justfile +++ b/justfile @@ -1,4 +1,7 @@ default: up up: - air go run *.go \ No newline at end of file + air go run *.go + +lint: + golangci-lint run diff --git a/utils.go b/utils.go index 26411eb..26de694 100644 --- a/utils.go +++ b/utils.go @@ -23,16 +23,6 @@ func stringInSlice(a string, list []string) bool { return false } -func concatLabels(labels map[string]string) string { - var concatenatedLabels []string - - for key, value := range labels { - concatenatedLabels = append(concatenatedLabels, fmt.Sprintf("%s=%s", key, value)) - } - - return strings.Join(concatenatedLabels, ",") -} - // https://gist.github.com/r0l1/3dcbb0c8f6cfe9c66ab8008f55f8f28b func askForConfirmation(s string) bool { reader := bufio.NewReader(os.Stdin) From 7ecfa10c600ad8be41da5094d83697d21a5efc01 Mon Sep 17 00:00:00 2001 From: Tchoupinax Date: Thu, 11 Apr 2024 15:07:27 +0200 Subject: [PATCH 3/3] Update README.md Co-authored-by: ImOverlord <9958853+ImOverlord@users.noreply.github.com> --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a133fe9..4d08461 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,12 @@ kubernetes-labels-migrator \ ## Tutorial -Let's say you are managing your application with the gitops's philosohpy ([ArgoCD](https://argo-cd.readthedocs.io/en/stable/) is really great to do the job). You want to add or edit a label. This difference has already been done by your code but ArgoCD refused to sync because of the "immutable field" error. Then following this: -- ⚠️ First of all, nothing intervene during the operation! `kubernetes-labels-migrator` should be free until the end. If you have tools like ArgoCD that synchronize your resources, **please** ensure this feature is **disabled**. -- You can commit the changes on the resource and observe the difference -- Launch the script and watch the magic happens -- According your changes, the difference should have been resolved +Let's say you are managing your application with the GitOps philosophy (ArgoCD is really great for this job). You want to add or edit a label. This change has already been made in your code, but ArgoCD refused to sync due to the "immutable field" error. Here's what you should do: + +- ⚠️ First of all, ensure that nothing intervenes during the operation! kubernetes-labels-migrator should be free until the end. If you have tools like ArgoCD that synchronize your resources, please ensure this feature is disabled. +- Commit the changes to the resource and observe the difference. +- Launch the script and watch the magic happen. +- According to your changes, the difference should have been resolved. ## Motivation