Skip to content
Open
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
10 changes: 4 additions & 6 deletions controllers/argocd/applicationset.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,23 +277,21 @@ func (r *ReconcileArgoCD) reconcileApplicationSetDeployment(cr *argoproj.ArgoCD,
AddSeccompProfileForOpenShift(r.Client, podSpec)

if deplExists {
// Add Kubernetes-specific labels/annotations from the live object in the source to preserve metadata.
addKubernetesData(deploy.Spec.Template.Labels, existing.Spec.Template.Labels)
addKubernetesData(deploy.Spec.Template.Annotations, existing.Spec.Template.Annotations)
//Check if annotations have changed
UpdateMapValues(&existing.Spec.Template.Annotations, deploy.Spec.Template.Annotations)

// If the Deployment already exists, make sure the values we care about are up-to-date
deploymentsDifferent := identifyDeploymentDifference(*existing, *deploy)
if len(deploymentsDifferent) > 0 {
existing.Spec.Template.Spec.Containers = podSpec.Containers
existing.Spec.Template.Spec.Volumes = podSpec.Volumes
existing.Spec.Template.Spec.ServiceAccountName = podSpec.ServiceAccountName
existing.Labels = deploy.Labels
existing.Spec.Template.Labels = deploy.Spec.Template.Labels
UpdateMapValues(&existing.Labels, deploy.Labels)
UpdateMapValues(&existing.Spec.Template.Labels, deploy.Spec.Template.Labels)
existing.Spec.Selector = deploy.Spec.Selector
existing.Spec.Template.Spec.NodeSelector = deploy.Spec.Template.Spec.NodeSelector
existing.Spec.Template.Spec.Tolerations = deploy.Spec.Template.Spec.Tolerations
existing.Spec.Template.Spec.Containers[0].SecurityContext = deploy.Spec.Template.Spec.Containers[0].SecurityContext
existing.Spec.Template.Annotations = deploy.Spec.Template.Annotations

argoutil.LogResourceUpdate(log, existing, "due to difference in", deploymentsDifferent)
return r.Update(context.TODO(), existing)
Expand Down
25 changes: 25 additions & 0 deletions controllers/argocd/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,25 @@ func (r *ReconcileArgoCD) reconcileConfigMaps(cr *argoproj.ArgoCD, useTLSForRedi
// This ConfigMap holds the CA Certificate data for client use.
func (r *ReconcileArgoCD) reconcileCAConfigMap(cr *argoproj.ArgoCD) error {
cm := newConfigMapWithName(getCAConfigMapName(cr), cr)
existingCM := &corev1.ConfigMap{}
exists, err := argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, existingCM)
if err != nil {
return err
}
if exists {
changed := false
//Check if labels have changed
if UpdateMapValues(&existingCM.Labels, cm.GetLabels()) {
argoutil.LogResourceUpdate(log, existingCM, "updating", "CAConfigMap labels")
changed = true
if changed {
if err := r.Update(context.TODO(), existingCM); err != nil {
log.Error(err, "failed to update service object")
}
}
}

}

configMapExists, err := argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm)
if err != nil {
Expand Down Expand Up @@ -535,6 +554,12 @@ func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoproj.ArgoCD) error {
}

changed := false
//Check if labels have changed
if UpdateMapValues(&existingCM.Labels, cm.GetLabels()) {
argoutil.LogResourceUpdate(log, existingCM, "updating", "ConfigMap labels")
changed = true
}

if !reflect.DeepEqual(cm.Data, existingCM.Data) {
existingCM.Data = cm.Data
changed = true
Expand Down
12 changes: 4 additions & 8 deletions controllers/argocd/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -1249,20 +1249,16 @@ func (r *ReconcileArgoCD) reconcileServerDeployment(cr *argoproj.ArgoCD, useTLSF
}
}

// Add Kubernetes-specific labels/annotations from the live object in the source to preserve metadata.
addKubernetesData(deploy.Spec.Template.Labels, existing.Spec.Template.Labels)
addKubernetesData(deploy.Spec.Template.Annotations, existing.Spec.Template.Annotations)

if !reflect.DeepEqual(deploy.Spec.Template.Annotations, existing.Spec.Template.Annotations) {
existing.Spec.Template.Annotations = deploy.Spec.Template.Annotations
//Check if labels/annotations have changed
if UpdateMapValues(&existing.Spec.Template.Annotations, deploy.Spec.Template.Annotations) {
if changed {
explanation += ", "
}
explanation += "annotations"
changed = true
}
if !reflect.DeepEqual(deploy.Spec.Template.Labels, existing.Spec.Template.Labels) {
existing.Spec.Template.Labels = deploy.Spec.Template.Labels
// Preserve non-operator labels in the existing deployment.
if UpdateMapValues(&existing.Spec.Template.Labels, deploy.Spec.Template.Labels) {
if changed {
explanation += ", "
}
Expand Down
11 changes: 3 additions & 8 deletions controllers/argocd/repo_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,21 +513,16 @@ func (r *ReconcileArgoCD) reconcileRepoDeployment(cr *argocdoperatorv1beta1.Argo
changed = true
}

// Add Kubernetes-specific labels/annotations from the live object in the source to preserve metadata.
addKubernetesData(deploy.Spec.Template.Labels, existing.Spec.Template.Labels)
addKubernetesData(deploy.Spec.Template.Annotations, existing.Spec.Template.Annotations)

if !reflect.DeepEqual(deploy.Spec.Template.Annotations, existing.Spec.Template.Annotations) {
existing.Spec.Template.Annotations = deploy.Spec.Template.Annotations
//Check if labels/annotations have changed
if UpdateMapValues(&existing.Spec.Template.Annotations, deploy.Spec.Template.Annotations) {
if changed {
explanation += ", "
}
explanation += "annotations"
changed = true
}

if !reflect.DeepEqual(deploy.Spec.Template.Labels, existing.Spec.Template.Labels) {
existing.Spec.Template.Labels = deploy.Spec.Template.Labels
if UpdateMapValues(&existing.Spec.Template.Labels, deploy.Spec.Template.Labels) {
if changed {
explanation += ", "
}
Expand Down
6 changes: 2 additions & 4 deletions controllers/argocd/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,7 @@ func matchAggregatedClusterRoleFields(expectedClusterRole *v1.ClusterRole, exist

// if ClusterRole is for View permissions then compare Labels
if name == common.ArgoCDApplicationControllerComponentView {
if !reflect.DeepEqual(existingClusterRole.Labels, expectedClusterRole.Labels) {
existingClusterRole.Labels = expectedClusterRole.Labels
if UpdateMapValues(&existingClusterRole.Labels, expectedClusterRole.Labels) {
if changed {
explanation += ", "
}
Expand All @@ -535,8 +534,7 @@ func matchAggregatedClusterRoleFields(expectedClusterRole *v1.ClusterRole, exist
changed = true
}

if !reflect.DeepEqual(existingClusterRole.Labels, expectedClusterRole.Labels) {
existingClusterRole.Labels = expectedClusterRole.Labels
if UpdateMapValues(&existingClusterRole.Labels, expectedClusterRole.Labels) {
if changed {
explanation += ", "
}
Expand Down
11 changes: 3 additions & 8 deletions controllers/argocd/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -984,21 +984,16 @@ func (r *ReconcileArgoCD) reconcileApplicationControllerStatefulSet(cr *argoproj
changed = true
}

// Add Kubernetes-specific labels/annotations from the live object in the source to preserve metadata.
addKubernetesData(ss.Spec.Template.Labels, existing.Spec.Template.Labels)
addKubernetesData(ss.Spec.Template.Annotations, existing.Spec.Template.Annotations)

if !reflect.DeepEqual(ss.Spec.Template.Annotations, existing.Spec.Template.Annotations) {
existing.Spec.Template.Annotations = ss.Spec.Template.Annotations
//Check if labels/annotations have changed
if UpdateMapValues(&existing.Spec.Template.Annotations, ss.Spec.Template.Annotations) {
if changed {
explanation += ", "
}
explanation += "annotations"
changed = true
}

if !reflect.DeepEqual(ss.Spec.Template.Labels, existing.Spec.Template.Labels) {
existing.Spec.Template.Labels = ss.Spec.Template.Labels
if UpdateMapValues(&existing.Spec.Template.Labels, ss.Spec.Template.Labels) {
if changed {
explanation += ", "
}
Expand Down
39 changes: 14 additions & 25 deletions controllers/argocd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -1606,29 +1606,20 @@ func UseServer(name string, cr *argoproj.ArgoCD) bool {
return true
}

// addKubernetesData checks for any Kubernetes-specific labels or annotations
// in the live object and updates the source object to ensure critical metadata
// (like scheduling, topology, or lifecycle information) is retained.
// This helps avoid loss of important Kubernetes-managed metadata during updates.
func addKubernetesData(source map[string]string, live map[string]string) {

// List of Kubernetes-specific substrings (wildcard match)
patterns := []string{
"*kubernetes.io*",
"*k8s.io*",
"*openshift.io*",
}

for key, value := range live {
found := glob.MatchStringInList(patterns, key, glob.GLOB)
if found {
// Don't override values already present in the source object.
// This allows the operator to update Kubernetes specific data when needed.
if _, ok := source[key]; !ok {
source[key] = value
}
// UpdateMapValues updates the values of an existing map with the values from a source map if they differ.
// It returns true if any values were changed.
func UpdateMapValues(existing *map[string]string, source map[string]string) bool {
changed := false
if *existing == nil {
*existing = make(map[string]string)
}
for key, value := range source {
if (*existing)[key] != value {
(*existing)[key] = value
changed = true
}
}
return changed
}

// updateStatusAndConditionsOfArgoCD will update .status field with provided param, and upsert .status.conditions with provided condition
Expand Down Expand Up @@ -2267,17 +2258,15 @@ func (r *ReconcileArgoCD) reconcileDeploymentHelper(cr *argoproj.ArgoCD, desired
deploymentChanged = true
}

if !reflect.DeepEqual(existingDeployment.Labels, desiredDeployment.Labels) {
existingDeployment.Labels = desiredDeployment.Labels
if UpdateMapValues(&existingDeployment.Labels, desiredDeployment.Labels) {
if deploymentChanged {
explanation += ", "
}
explanation += "labels"
deploymentChanged = true
}

if !reflect.DeepEqual(existingDeployment.Spec.Template.Labels, desiredDeployment.Spec.Template.Labels) {
existingDeployment.Spec.Template.Labels = desiredDeployment.Spec.Template.Labels
if UpdateMapValues(&existingDeployment.Spec.Template.Labels, desiredDeployment.Spec.Template.Labels) {
if deploymentChanged {
explanation += ", "
}
Expand Down
55 changes: 31 additions & 24 deletions controllers/argocd/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1169,69 +1169,76 @@ func TestReconcileArgoCD_reconcileDexOAuthClientSecret(t *testing.T) {
assert.True(t, tokenExists, "Dex is enabled but unable to create oauth client secret")
}

func TestRetainKubernetesData(t *testing.T) {
func TestUpdateMapValue(t *testing.T) {
tests := []struct {
name string
source map[string]string
live map[string]string
existing map[string]string
expected map[string]string
}{
{
name: "Add Kubernetes-specific keys not in source",
name: "Retain non-operator-specific keys not in source",
source: map[string]string{
"custom-label": "custom-value",
"node.kubernetes.io/pod": "true",
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30",
"openshift.openshift.io/restartedAt": "2024-12-05T09:46:46+05:30",
},
live: map[string]string{
existing: map[string]string{
"node.kubernetes.io/pod": "true",
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30",
"openshift.openshift.io/restartedAt": "2024-12-05T09:46:46+05:30",
"custom-label": "custom-value",
},
expected: map[string]string{
"custom-label": "custom-value", // unchanged
"node.kubernetes.io/pod": "true", // added
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30", // added
"openshift.openshift.io/restartedAt": "2024-12-05T09:46:46+05:30", // added
"custom-label": "custom-value", // retained from existing
"node.kubernetes.io/pod": "true", // unchanged
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30", // unchanged
"openshift.openshift.io/restartedAt": "2024-12-05T09:46:46+05:30", // unchanged
},
},
{
name: "Ignores non-Kubernetes-specific keys",
name: "Override operator-specific keys in live with source",
source: map[string]string{
"custom-label": "custom-value",
"node.kubernetes.io/pod": "source-true",
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30",
},
live: map[string]string{
"non-k8s-key": "non-k8s-value",
"custom-label": "live-value",
existing: map[string]string{
"node.kubernetes.io/pod": "live-true", // should override
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30",
},
expected: map[string]string{
"custom-label": "custom-value", // unchanged
"node.kubernetes.io/pod": "source-true",
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30",
},
},
{
name: "Do not override existing Kubernetes-specific keys in source",
name: "Retain existing operator-specific keys from source",
source: map[string]string{
"node.kubernetes.io/pod": "source-true",
"node.kubernetes.io/pod": "source-true",
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30",
},
live: map[string]string{
"node.kubernetes.io/pod": "live-true", // should not override
existing: map[string]string{
"node.kubernetes.io/pod": "source-true",
},
expected: map[string]string{
"node.kubernetes.io/pod": "source-true", // source takes precedence
"node.kubernetes.io/pod": "source-true",
"kubectl.kubernetes.io/restartedAt": "2024-12-05T09:46:46+05:30",
},
},
{
name: "Handles empty live map",
source: map[string]string{
"custom-label": "custom-value",
},
live: map[string]string{},
existing: map[string]string{},
expected: map[string]string{
"custom-label": "custom-value", // unchanged
},
},
{
name: "Handles empty source map",
source: map[string]string{},
live: map[string]string{
existing: map[string]string{
"openshift.io/resource": "value",
},
expected: map[string]string{
Expand All @@ -1242,8 +1249,8 @@ func TestRetainKubernetesData(t *testing.T) {

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
addKubernetesData(tt.source, tt.live)
assert.Equal(t, tt.expected, tt.source)
UpdateMapValues(&tt.existing, tt.source)
assert.Equal(t, tt.expected, tt.existing)
})
}
}
Expand Down
Loading