Skip to content

Commit 556a721

Browse files
authored
Merge pull request #627 from mohtork/fix/preserve-argocd-spec-fields-on-update
fix: preserve existing ArgoCD spec fields during update
2 parents d536317 + 1d48c50 commit 556a721

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

internal/controller/argo.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,20 @@ func createOrUpdateArgoCD(client dynamic.Interface, fullClient kubernetes.Interf
480480
}
481481
newArgo := &unstructured.Unstructured{Object: obj}
482482

483+
// Preserve spec fields not known to this vendored argocd-operator version
484+
// (e.g. networkPolicy added in gitops-operator v1.20.3) to avoid
485+
// stripping them and causing infinite reconciliation loops.
486+
oldUnstructured, errGet2 := client.Resource(gvr).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
487+
if errGet2 == nil {
488+
oldSpec, _, _ := unstructured.NestedMap(oldUnstructured.Object, "spec")
489+
newSpec, _, _ := unstructured.NestedMap(newArgo.Object, "spec")
490+
for key, val := range oldSpec {
491+
if _, exists := newSpec[key]; !exists {
492+
_ = unstructured.SetNestedField(newArgo.Object, val, "spec", key)
493+
}
494+
}
495+
}
496+
483497
_, err = client.Resource(gvr).Namespace(namespace).Update(context.TODO(), newArgo, metav1.UpdateOptions{})
484498
}
485499
return err

internal/controller/argo_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,53 @@ var _ = Describe("CreateOrUpdateArgoCD", func() {
10201020
})
10211021
})
10221022

1023+
Context("when the ArgoCD instance exists with additional spec fields not managed by patterns-operator", func() {
1024+
BeforeEach(func() {
1025+
argoCD := &unstructured.Unstructured{
1026+
Object: map[string]any{
1027+
"apiVersion": "argoproj.io/v1beta1",
1028+
"kind": "ArgoCD",
1029+
"metadata": map[string]any{
1030+
"name": name,
1031+
"namespace": namespace,
1032+
"resourceVersion": "1",
1033+
},
1034+
"spec": map[string]any{
1035+
"networkPolicy": map[string]any{
1036+
"enabled": true,
1037+
},
1038+
"imageUpdater": map[string]any{
1039+
"enabled": false,
1040+
},
1041+
},
1042+
},
1043+
}
1044+
_, err := dynamicClient.Resource(gvr).Namespace(namespace).Create(context.TODO(), argoCD, metav1.CreateOptions{})
1045+
Expect(err).ToNot(HaveOccurred())
1046+
})
1047+
1048+
It("should preserve spec fields not managed by patterns-operator during update", func() {
1049+
err := createOrUpdateArgoCD(dynamicClient, nil, name, namespace, patternsOperatorConfig)
1050+
Expect(err).ToNot(HaveOccurred())
1051+
1052+
argoCD, err := dynamicClient.Resource(gvr).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
1053+
Expect(err).ToNot(HaveOccurred())
1054+
1055+
// networkPolicy should be preserved — it is managed by gitops-operator
1056+
// not by patterns-operator, so the update must not strip it
1057+
networkPolicy, found, err := unstructured.NestedMap(argoCD.Object, "spec", "networkPolicy")
1058+
Expect(err).ToNot(HaveOccurred())
1059+
Expect(found).To(BeTrue(), "networkPolicy should be preserved after update")
1060+
Expect(networkPolicy["enabled"]).To(BeTrue())
1061+
1062+
// imageUpdater should also be preserved
1063+
imageUpdater, found, err := unstructured.NestedMap(argoCD.Object, "spec", "imageUpdater")
1064+
Expect(err).ToNot(HaveOccurred())
1065+
Expect(found).To(BeTrue(), "imageUpdater should be preserved after update")
1066+
Expect(imageUpdater["enabled"]).To(BeFalse())
1067+
})
1068+
})
1069+
10231070
Context("when there is an error in the getArgoCD fn but there is an argocd", func() {
10241071

10251072
BeforeEach(func() {

0 commit comments

Comments
 (0)