From 022b4f4eb93736bd7af7640339c5d90914d9b64e Mon Sep 17 00:00:00 2001 From: John Pitman Date: Thu, 12 Dec 2024 10:51:11 -0500 Subject: [PATCH] feat: log k8s create/update/delete actions (#1615) * feat: log k8s create/update/delete actions Signed-off-by: John Pitman * fix linter errors Signed-off-by: John Pitman * add nil check to LogResourceAction Signed-off-by: John Pitman --------- Signed-off-by: John Pitman --- controllers/argocd/applicationset.go | 104 +++++++++-- controllers/argocd/configmap.go | 42 ++++- controllers/argocd/configmap_test.go | 10 +- controllers/argocd/deployment.go | 175 +++++++++++++++++- controllers/argocd/deployment_test.go | 12 +- controllers/argocd/dex.go | 51 ++++- controllers/argocd/hpa.go | 3 + controllers/argocd/ingress.go | 52 +++++- controllers/argocd/keycloak.go | 27 ++- controllers/argocd/networkpolicies.go | 28 ++- controllers/argocd/notifications.go | 80 ++++++-- controllers/argocd/prometheus.go | 12 +- controllers/argocd/role.go | 78 +++++++- controllers/argocd/rolebinding.go | 16 +- controllers/argocd/route.go | 21 +++ controllers/argocd/secret.go | 23 ++- controllers/argocd/service.go | 47 ++++- controllers/argocd/service_account.go | 5 +- controllers/argocd/statefulset.go | 97 +++++++++- controllers/argocd/statefulset_test.go | 15 +- controllers/argocd/util.go | 9 + controllers/argocdexport/export.go | 2 + controllers/argocdexport/job.go | 3 + controllers/argocdexport/local.go | 4 +- controllers/argocdexport/storage.go | 2 + controllers/argoutil/resource.go | 52 ++++++ controllers/argoutil/secret.go | 2 + .../notificationsconfiguration/configmap.go | 2 + .../notificationsconfiguration_controller.go | 2 + .../02-ingress-available.yaml | 2 +- .../03-disable-admin.yaml | 2 +- tests/k8s/1-001_validate_basic/04-export.yaml | 2 +- .../05-applicationset.yaml | 4 +- 33 files changed, 881 insertions(+), 105 deletions(-) diff --git a/controllers/argocd/applicationset.go b/controllers/argocd/applicationset.go index 0b6168a36..50a8ab8ce 100644 --- a/controllers/argocd/applicationset.go +++ b/controllers/argocd/applicationset.go @@ -22,6 +22,7 @@ import ( "reflect" "strings" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -169,6 +170,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetDeployment(cr *argoproj.ArgoCD, } if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.IsEnabled() { if exists { + argoutil.LogResourceDeletion(log, existing, "application set not enabled") return r.Client.Delete(context.TODO(), existing) } return nil @@ -269,26 +271,13 @@ func (r *ReconcileArgoCD) reconcileApplicationSetDeployment(cr *argoproj.ArgoCD, AddSeccompProfileForOpenShift(r.Client, podSpec) if exists { - - existingSpec := existing.Spec.Template.Spec - // 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) - deploymentsDifferent := !reflect.DeepEqual(existingSpec.Containers[0], podSpec.Containers) || - !reflect.DeepEqual(existingSpec.Volumes, podSpec.Volumes) || - existingSpec.ServiceAccountName != podSpec.ServiceAccountName || - !reflect.DeepEqual(existing.Labels, deploy.Labels) || - !reflect.DeepEqual(existing.Spec.Template.Labels, deploy.Spec.Template.Labels) || - !reflect.DeepEqual(existing.Spec.Selector, deploy.Spec.Selector) || - !reflect.DeepEqual(existing.Spec.Template.Spec.NodeSelector, deploy.Spec.Template.Spec.NodeSelector) || - !reflect.DeepEqual(existing.Spec.Template.Spec.Tolerations, deploy.Spec.Template.Spec.Tolerations) || - !reflect.DeepEqual(existing.Spec.Template.Spec.Containers[0].SecurityContext, deploy.Spec.Template.Spec.Containers[0].SecurityContext) || - !reflect.DeepEqual(existing.Spec.Template.Annotations, deploy.Spec.Template.Annotations) - // If the Deployment already exists, make sure the values we care about are up-to-date - if deploymentsDifferent { + 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 @@ -300,6 +289,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetDeployment(cr *argoproj.ArgoCD, 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.Client.Update(context.TODO(), existing) } return nil // Deployment found with nothing to do, move along... @@ -312,10 +302,62 @@ func (r *ReconcileArgoCD) reconcileApplicationSetDeployment(cr *argoproj.ArgoCD, if err := controllerutil.SetControllerReference(cr, deploy, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, deploy) return r.Client.Create(context.TODO(), deploy) } +// identifyDeploymentDifference is a simple comparison of the contents of two +// deployments, returning "" if they are the same, otherwise returning the name +// of the field that changed. +func identifyDeploymentDifference(x appsv1.Deployment, y appsv1.Deployment) string { + + xPodSpec := x.Spec.Template.Spec + yPodSpec := y.Spec.Template.Spec + + if !reflect.DeepEqual(xPodSpec.Containers, yPodSpec.Containers) { + return ".Spec.Template.Spec.Containers" + } + + if !reflect.DeepEqual(xPodSpec.Volumes, yPodSpec.Volumes) { + return ".Spec.Template.Spec.Volumes" + } + + if xPodSpec.ServiceAccountName != yPodSpec.ServiceAccountName { + return "ServiceAccountName" + } + + if !reflect.DeepEqual(x.Labels, y.Labels) { + return "Labels" + } + + if !reflect.DeepEqual(x.Spec.Template.Labels, y.Spec.Template.Labels) { + return ".Spec.Template.Labels" + } + + if !reflect.DeepEqual(x.Spec.Selector, y.Spec.Selector) { + return ".Spec.Selector" + } + + if !reflect.DeepEqual(xPodSpec.NodeSelector, yPodSpec.NodeSelector) { + return "Spec.Template.Spec.NodeSelector" + } + + if !reflect.DeepEqual(xPodSpec.Tolerations, yPodSpec.Tolerations) { + return "Spec.Template.Spec.Tolerations" + } + + if !reflect.DeepEqual(xPodSpec.Containers[0].SecurityContext, yPodSpec.Containers[0].SecurityContext) { + return "Spec.Template.Spec..Containers[0].SecurityContext" + } + + if !reflect.DeepEqual(x.Spec.Template.Annotations, y.Spec.Template.Annotations) { + return ".Spec.Template.Annotations" + } + + return "" +} + func (r *ReconcileArgoCD) applicationSetContainer(cr *argoproj.ArgoCD, addSCMGitlabVolumeMount bool) corev1.Container { // Global proxy env vars go first appSetEnv := []corev1.EnvVar{{ @@ -419,6 +461,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetServiceAccount(cr *argoproj.Arg if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.IsEnabled() { if exists { + argoutil.LogResourceDeletion(log, sa, "application set not enabled") err := r.Client.Delete(context.TODO(), sa) if err != nil { if !apierrors.IsNotFound(err) { @@ -434,6 +477,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetServiceAccount(cr *argoproj.Arg return sa, err } + argoutil.LogResourceCreation(log, sa) err := r.Client.Create(context.TODO(), sa) if err != nil { return sa, err @@ -497,11 +541,13 @@ func (r *ReconcileArgoCD) reconcileApplicationSetClusterRole(cr *argoproj.ArgoCD // Do Nothing return clusterRole, nil } + argoutil.LogResourceCreation(log, clusterRole) return clusterRole, r.Client.Create(context.TODO(), clusterRole) } // ArgoCD not cluster scoped, cleanup any existing resource and exit if !allowed { + argoutil.LogResourceDeletion(log, existingClusterRole, "argocd not cluster scoped") err := r.Client.Delete(context.TODO(), existingClusterRole) if err != nil { if !apierrors.IsNotFound(err) { @@ -514,6 +560,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetClusterRole(cr *argoproj.ArgoCD // if the Rules differ, update the Role if !reflect.DeepEqual(existingClusterRole.Rules, clusterRole.Rules) { existingClusterRole.Rules = clusterRole.Rules + argoutil.LogResourceUpdate(log, existingClusterRole, "updating rules") if err := r.Client.Update(context.TODO(), existingClusterRole); err != nil { return nil, err } @@ -561,11 +608,13 @@ func (r *ReconcileArgoCD) reconcileApplicationSetClusterRoleBinding(cr *argoproj // Do Nothing return nil } + argoutil.LogResourceCreation(log, clusterRB) return r.Client.Create(context.TODO(), clusterRB) } // ArgoCD not cluster scoped, cleanup any existing resource and exit if !allowed { + argoutil.LogResourceDeletion(log, existingClusterRB, "argocd not cluster scoped") err := r.Client.Delete(context.TODO(), existingClusterRB) if err != nil { if !apierrors.IsNotFound(err) { @@ -578,11 +627,13 @@ func (r *ReconcileArgoCD) reconcileApplicationSetClusterRoleBinding(cr *argoproj // if subj differ, update the rolebinding if !reflect.DeepEqual(existingClusterRB.Subjects, clusterRB.Subjects) { existingClusterRB.Subjects = clusterRB.Subjects + argoutil.LogResourceUpdate(log, existingClusterRB, "updating subjects") if err := r.Client.Update(context.TODO(), existingClusterRB); err != nil { return err } } else if !reflect.DeepEqual(existingClusterRB.RoleRef, clusterRB.RoleRef) { // RoleRef can't be updated, delete the rolebinding so that it gets recreated + argoutil.LogResourceDeletion(log, existingClusterRB, "roleref changed, deleting rolebinding so it gets recreated") _ = r.Client.Delete(context.TODO(), existingClusterRB) return fmt.Errorf("change detected in roleRef for rolebinding %s of Argo CD instance %s in namespace %s", existingClusterRB.Name, cr.Name, existingClusterRB.Namespace) } @@ -649,6 +700,8 @@ func (r *ReconcileArgoCD) reconcileApplicationSetSourceNamespacesResources(cr *a namespace.Labels = make(map[string]string) } namespace.Labels[common.ArgoCDApplicationSetManagedByClusterArgoCDLabel] = cr.Namespace + explanation := fmt.Sprintf("adding label '%s=%s'", common.ArgoCDApplicationSetManagedByClusterArgoCDLabel, cr.Namespace) + argoutil.LogResourceUpdate(log, namespace, explanation) if err := r.Client.Update(context.TODO(), namespace); err != nil { log.Error(err, fmt.Sprintf("failed to add label from namespace [%s]", namespace.Name)) } @@ -724,6 +777,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetRole(cr *argoproj.ArgoCD) (*v1. if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.IsEnabled() { if exists { + argoutil.LogResourceDeletion(log, role, "application set not enabled") if err := r.Client.Delete(context.TODO(), role); err != nil { if !apierrors.IsNotFound(err) { return role, err @@ -738,8 +792,10 @@ func (r *ReconcileArgoCD) reconcileApplicationSetRole(cr *argoproj.ArgoCD) (*v1. return role, err } if exists { + argoutil.LogResourceUpdate(log, role) return role, r.Client.Update(context.TODO(), role) } else { + argoutil.LogResourceCreation(log, role) return role, r.Client.Create(context.TODO(), role) } @@ -763,6 +819,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetRoleBinding(cr *argoproj.ArgoCD if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.IsEnabled() { if roleBindingExists { + argoutil.LogResourceDeletion(log, roleBinding, "application set not enabled") return r.Client.Delete(context.TODO(), roleBinding) } return nil @@ -789,9 +846,11 @@ func (r *ReconcileArgoCD) reconcileApplicationSetRoleBinding(cr *argoproj.ArgoCD } if roleBindingExists { + argoutil.LogResourceUpdate(log, roleBinding) return r.Client.Update(context.TODO(), roleBinding) } + argoutil.LogResourceCreation(log, roleBinding) return r.Client.Create(context.TODO(), roleBinding) } @@ -853,7 +912,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetService(cr *argoproj.ArgoCD) er if err != nil { return err } - log.Info(fmt.Sprintf("Deleting applicationset controller service %s as applicationset is disabled", svc.Name)) + argoutil.LogResourceDeletion(log, svc, "application set not enabled") err = r.Delete(context.TODO(), svc) if err != nil { return err @@ -886,6 +945,7 @@ func (r *ReconcileArgoCD) reconcileApplicationSetService(cr *argoproj.ArgoCD) er if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -944,6 +1004,7 @@ func (r *ReconcileArgoCD) cleanupUnmanagedApplicationSetSourceNamespaceResources } } if existingRole.Name != "" { + argoutil.LogResourceDeletion(log, &existingRole, "cleaning up unmanaged application set resources") err := r.Client.Delete(context.TODO(), &existingRole) if err != nil { return err @@ -958,6 +1019,7 @@ func (r *ReconcileArgoCD) cleanupUnmanagedApplicationSetSourceNamespaceResources } } if existingRoleBinding.Name != "" { + argoutil.LogResourceDeletion(log, existingRoleBinding, "cleaning up unmanaged application set resources") if err := r.Client.Delete(context.TODO(), existingRoleBinding); err != nil { return err } @@ -966,6 +1028,7 @@ func (r *ReconcileArgoCD) cleanupUnmanagedApplicationSetSourceNamespaceResources // app-in-any-ns code will handle removal of appsets permissions for argocd-server in target namespace // Remove applicationset-managed-by-cluster-argocd label from the namespace + argoutil.LogResourceUpdate(log, &namespace, "removing label", common.ArgoCDApplicationSetManagedByClusterArgoCDLabel) delete(namespace.Labels, common.ArgoCDApplicationSetManagedByClusterArgoCDLabel) if err := r.Client.Update(context.TODO(), &namespace); err != nil { return fmt.Errorf("failed to remove applicationset label from namespace %s : %s", namespace.Name, err) @@ -1012,6 +1075,7 @@ func (r *ReconcileArgoCD) reconcileSourceNamespaceRole(role v1.Role, cr *argopro return errors.Join(errMsg, err) } + argoutil.LogResourceCreation(log, &role) if err := r.Client.Create(context.TODO(), &role); err != nil { errMsg := fmt.Errorf("failed to create role %s in namespace %s", role.Name, role.Namespace) return errors.Join(errMsg, err) @@ -1024,11 +1088,11 @@ func (r *ReconcileArgoCD) reconcileSourceNamespaceRole(role v1.Role, cr *argopro // if the Rules differ, update the Role, ignore if role is just created. if !reflect.DeepEqual(existingRole.Rules, role.Rules) { existingRole.Rules = role.Rules + argoutil.LogResourceUpdate(log, &existingRole, "updating rules") if err := r.Client.Update(context.TODO(), &existingRole); err != nil { errMsg := fmt.Errorf("failed to update role %s in namespace %s", role.Name, role.Namespace) return errors.Join(errMsg, err) } - log.Info(fmt.Sprintf("role %s update successfully for Argo CD instance %s in namespace %s", role.Name, cr.Name, role.Namespace)) } return nil @@ -1049,17 +1113,17 @@ func (r *ReconcileArgoCD) reconcileSourceNamespaceRoleBinding(roleBinding v1.Rol return errors.Join(errMsg, err) } + argoutil.LogResourceCreation(log, &roleBinding) if err := r.Client.Create(context.TODO(), &roleBinding); err != nil { errMsg := fmt.Errorf("failed to create rolebinding %s in namespace %s", roleBinding.Name, roleBinding.Namespace) return errors.Join(errMsg, err) } - - log.Info(fmt.Sprintf("rolebinding %s created successfully for Argo CD instance %s in namespace %s", roleBinding.Name, cr.Name, roleBinding.Namespace)) return nil } // if the RoleRef changes, delete the existing role binding and create a new one if !reflect.DeepEqual(roleBinding.RoleRef, existingRoleBinding.RoleRef) { + argoutil.LogResourceDeletion(log, &existingRoleBinding, "roleref changed, deleting rolebinding so it gets recreated") if err = r.Client.Delete(context.TODO(), &existingRoleBinding); err != nil { return err } @@ -1067,10 +1131,10 @@ func (r *ReconcileArgoCD) reconcileSourceNamespaceRoleBinding(roleBinding v1.Rol // if the Subjects differ, update the role bindings if !reflect.DeepEqual(roleBinding.Subjects, existingRoleBinding.Subjects) { existingRoleBinding.Subjects = roleBinding.Subjects + argoutil.LogResourceUpdate(log, &existingRoleBinding, "updating subjects") if err = r.Client.Update(context.TODO(), &existingRoleBinding); err != nil { return err } - log.Info(fmt.Sprintf("rolebinding %s update successfully for Argo CD instance %s in namespace %s", roleBinding.Name, cr.Name, roleBinding.Namespace)) } } diff --git a/controllers/argocd/configmap.go b/controllers/argocd/configmap.go index 19640c2e6..86e737acb 100644 --- a/controllers/argocd/configmap.go +++ b/controllers/argocd/configmap.go @@ -42,6 +42,7 @@ func (r *ReconcileArgoCD) createRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } @@ -371,6 +372,7 @@ func (r *ReconcileArgoCD) reconcileCAConfigMap(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } @@ -481,10 +483,10 @@ func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoproj.ArgoCD) error { changed = true } - // Compare OwnerReferences + // Check OwnerReferences var refChanged bool var err error - if refChanged, err = validateOwnerReferences(cr, existingCM, r.Scheme); err != nil { + if refChanged, err = modifyOwnerReferenceIfNeeded(cr, existingCM, r.Scheme); err != nil { return err } @@ -493,10 +495,16 @@ func (r *ReconcileArgoCD) reconcileArgoConfigMap(cr *argoproj.ArgoCD) error { } if changed { + explanation := "updating data" + if refChanged { + explanation += ", owner reference" + } + argoutil.LogResourceUpdate(log, existingCM, explanation) return r.Client.Update(context.TODO(), existingCM) } return nil // Do nothing as there is no change in the configmap. } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } @@ -537,39 +545,56 @@ func (r *ReconcileArgoCD) reconcileRBAC(cr *argoproj.ArgoCD) error { // reconcileRBACConfigMap will ensure that the RBAC ConfigMap is syncronized with the given ArgoCD. func (r *ReconcileArgoCD) reconcileRBACConfigMap(cm *corev1.ConfigMap, cr *argoproj.ArgoCD) error { changed := false + explanation := "" // Policy CSV if cr.Spec.RBAC.Policy != nil && cm.Data[common.ArgoCDKeyRBACPolicyCSV] != *cr.Spec.RBAC.Policy { cm.Data[common.ArgoCDKeyRBACPolicyCSV] = *cr.Spec.RBAC.Policy + explanation = "rbac policy" changed = true } // Default Policy if cr.Spec.RBAC.DefaultPolicy != nil && cm.Data[common.ArgoCDKeyRBACPolicyDefault] != *cr.Spec.RBAC.DefaultPolicy { cm.Data[common.ArgoCDKeyRBACPolicyDefault] = *cr.Spec.RBAC.DefaultPolicy + if changed { + explanation += ", " + } + explanation += " rbac default policy" changed = true } // Default Policy Matcher Mode if cr.Spec.RBAC.PolicyMatcherMode != nil && cm.Data[common.ArgoCDPolicyMatcherMode] != *cr.Spec.RBAC.PolicyMatcherMode { cm.Data[common.ArgoCDPolicyMatcherMode] = *cr.Spec.RBAC.PolicyMatcherMode + if changed { + explanation += ", " + } + explanation += "rbac policy matcher mode" changed = true } // Scopes if cr.Spec.RBAC.Scopes != nil && cm.Data[common.ArgoCDKeyRBACScopes] != *cr.Spec.RBAC.Scopes { cm.Data[common.ArgoCDKeyRBACScopes] = *cr.Spec.RBAC.Scopes + if changed { + explanation += ", " + } + explanation += "rbac scopes" changed = true } if changed { + argoutil.LogResourceUpdate(log, cm, "updating", explanation) // TODO: Reload server (and dex?) if RBAC settings change? return r.Client.Update(context.TODO(), cm) } return nil // ConfigMap exists and nothing to do, move along... } -// validateOwnerReferences checks if OwnerReferences is changed -func validateOwnerReferences(cr *argoproj.ArgoCD, cm *corev1.ConfigMap, scheme *runtime.Scheme) (bool, error) { +// modifyOwnerReferenceIfNeeded reverts any changes to the OwnerReference of the +// given config map. Returns true if the owner reference was modified, false if +// not. +func modifyOwnerReferenceIfNeeded(cr *argoproj.ArgoCD, cm *corev1.ConfigMap, scheme *runtime.Scheme) (bool, error) { changed := false if cm.OwnerReferences != nil { @@ -629,6 +654,7 @@ func (r *ReconcileArgoCD) reconcileRedisHAHealthConfigMap(cr *argoproj.ArgoCD, u if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { if !cr.Spec.HA.Enabled { // ConfigMap exists but HA enabled flag has been set to false, delete the ConfigMap + argoutil.LogResourceDeletion(log, cm, "redis ha is disabled") return r.Client.Delete(context.TODO(), cm) } return nil // ConfigMap found with nothing changed, move along... @@ -647,6 +673,7 @@ func (r *ReconcileArgoCD) reconcileRedisHAHealthConfigMap(cr *argoproj.ArgoCD, u if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } @@ -656,6 +683,7 @@ func (r *ReconcileArgoCD) reconcileRedisHAConfigMap(cr *argoproj.ArgoCD, useTLSF if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { if !cr.Spec.HA.Enabled { // ConfigMap exists but HA enabled flag has been set to false, delete the ConfigMap + argoutil.LogResourceDeletion(log, cm, "redis ha is disabled") return r.Client.Delete(context.TODO(), cm) } return nil // ConfigMap found with nothing changed, move along... @@ -676,12 +704,14 @@ func (r *ReconcileArgoCD) reconcileRedisHAConfigMap(cr *argoproj.ArgoCD, useTLSF if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } func (r *ReconcileArgoCD) recreateRedisHAConfigMap(cr *argoproj.ArgoCD, useTLSForRedis bool) error { cm := newConfigMapWithName(common.ArgoCDRedisHAConfigMapName, cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { + argoutil.LogResourceDeletion(log, cm, "deleting config map in order to recreate it") if err := r.Client.Delete(context.TODO(), cm); err != nil { return err } @@ -692,6 +722,7 @@ func (r *ReconcileArgoCD) recreateRedisHAConfigMap(cr *argoproj.ArgoCD, useTLSFo func (r *ReconcileArgoCD) recreateRedisHAHealthConfigMap(cr *argoproj.ArgoCD, useTLSForRedis bool) error { cm := newConfigMapWithName(common.ArgoCDRedisHAHealthConfigMapName, cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, cm.Name, cm) { + argoutil.LogResourceDeletion(log, cm, "deleting config map in order to recreate it") if err := r.Client.Delete(context.TODO(), cm); err != nil { return err } @@ -713,6 +744,7 @@ func (r *ReconcileArgoCD) reconcileSSHKnownHosts(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } @@ -728,6 +760,7 @@ func (r *ReconcileArgoCD) reconcileTLSCerts(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } @@ -740,5 +773,6 @@ func (r *ReconcileArgoCD) reconcileGPGKeysConfigMap(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, cm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cm) return r.Client.Create(context.TODO(), cm) } diff --git a/controllers/argocd/configmap_test.go b/controllers/argocd/configmap_test.go index 64fb94c3c..373d8afb2 100644 --- a/controllers/argocd/configmap_test.go +++ b/controllers/argocd/configmap_test.go @@ -1102,7 +1102,7 @@ func Test_validateOwnerReferences(t *testing.T) { cm := newConfigMapWithName(common.ArgoCDConfigMapName, a) // verify when OwnerReferences is not set - _, err := validateOwnerReferences(a, cm, r.Scheme) + _, err := modifyOwnerReferenceIfNeeded(a, cm, r.Scheme) assert.NoError(t, err) assert.Equal(t, cm.OwnerReferences[0].APIVersion, "argoproj.io/v1beta1") @@ -1113,7 +1113,7 @@ func Test_validateOwnerReferences(t *testing.T) { // verify when APIVersion is changed cm.OwnerReferences[0].APIVersion = "test" - changed, err := validateOwnerReferences(a, cm, r.Scheme) + changed, err := modifyOwnerReferenceIfNeeded(a, cm, r.Scheme) assert.NoError(t, err) assert.True(t, changed) assert.Equal(t, cm.OwnerReferences[0].APIVersion, "argoproj.io/v1beta1") @@ -1124,7 +1124,7 @@ func Test_validateOwnerReferences(t *testing.T) { // verify when Kind is changed cm.OwnerReferences[0].Kind = "test" - changed, err = validateOwnerReferences(a, cm, r.Scheme) + changed, err = modifyOwnerReferenceIfNeeded(a, cm, r.Scheme) assert.NoError(t, err) assert.True(t, changed) assert.Equal(t, cm.OwnerReferences[0].APIVersion, "argoproj.io/v1beta1") @@ -1135,7 +1135,7 @@ func Test_validateOwnerReferences(t *testing.T) { // verify when Kind is changed cm.OwnerReferences[0].Name = "test" - changed, err = validateOwnerReferences(a, cm, r.Scheme) + changed, err = modifyOwnerReferenceIfNeeded(a, cm, r.Scheme) assert.NoError(t, err) assert.True(t, changed) assert.Equal(t, cm.OwnerReferences[0].APIVersion, "argoproj.io/v1beta1") @@ -1146,7 +1146,7 @@ func Test_validateOwnerReferences(t *testing.T) { // verify when UID is changed cm.OwnerReferences[0].UID = "test" - changed, err = validateOwnerReferences(a, cm, r.Scheme) + changed, err = modifyOwnerReferenceIfNeeded(a, cm, r.Scheme) assert.NoError(t, err) assert.True(t, changed) assert.Equal(t, cm.OwnerReferences[0].APIVersion, "argoproj.io/v1beta1") diff --git a/controllers/argocd/deployment.go b/controllers/argocd/deployment.go index d120bb4f8..7ae7fb61e 100644 --- a/controllers/argocd/deployment.go +++ b/controllers/argocd/deployment.go @@ -532,48 +532,68 @@ func (r *ReconcileArgoCD) reconcileRedisDeployment(cr *argoproj.ArgoCD, useTLS b if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { if !cr.Spec.Redis.IsEnabled() { // Deployment exists but component enabled flag has been set to false, delete the Deployment - log.Info("Redis exists but should be disabled. Deleting existing redis.") + argoutil.LogResourceDeletion(log, deploy, "redis is disabled but deployment exists") return r.Client.Delete(context.TODO(), deploy) } else if cr.Spec.Redis.IsRemote() { - log.Info("Redis remote exists but redis deployment should be disabled. Deleting existing redis.") + argoutil.LogResourceDeletion(log, deploy, "remote redis is configured") return r.Client.Delete(context.TODO(), deploy) } if cr.Spec.HA.Enabled { // Deployment exists but HA enabled flag has been set to true, delete the Deployment + argoutil.LogResourceDeletion(log, deploy, "redis ha is enabled but non-ha deployment exists") return r.Client.Delete(context.TODO(), deploy) } changed := false + explanation := "" actualImage := existing.Spec.Template.Spec.Containers[0].Image desiredImage := getRedisContainerImage(cr) if actualImage != desiredImage { existing.Spec.Template.Spec.Containers[0].Image = desiredImage existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + explanation = "container image" changed = true } - updateNodePlacement(existing, deploy, &changed) + updateNodePlacement(existing, deploy, &changed, &explanation) if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Args, existing.Spec.Template.Spec.Containers[0].Args) { existing.Spec.Template.Spec.Containers[0].Args = deploy.Spec.Template.Spec.Containers[0].Args + if changed { + explanation += ", " + } + explanation += "container args" changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.Containers[0].Env, deploy.Spec.Template.Spec.Containers[0].Env) { existing.Spec.Template.Spec.Containers[0].Env = deploy.Spec.Template.Spec.Containers[0].Env + if changed { + explanation += ", " + } + explanation += "container env" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Resources, existing.Spec.Template.Spec.Containers[0].Resources) { existing.Spec.Template.Spec.Containers[0].Resources = deploy.Spec.Template.Spec.Containers[0].Resources + if changed { + explanation += ", " + } + explanation += "container resources" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].SecurityContext, existing.Spec.Template.Spec.Containers[0].SecurityContext) { existing.Spec.Template.Spec.Containers[0].SecurityContext = deploy.Spec.Template.Spec.Containers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if changed { + argoutil.LogResourceUpdate(log, existing, "updating", explanation) return r.Client.Update(context.TODO(), existing) } return nil // Deployment found with nothing to do, move along... @@ -595,6 +615,7 @@ func (r *ReconcileArgoCD) reconcileRedisDeployment(cr *argoproj.ArgoCD, useTLS b if err := controllerutil.SetControllerReference(cr, deploy, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, deploy) return r.Client.Create(context.TODO(), deploy) } @@ -800,40 +821,60 @@ func (r *ReconcileArgoCD) reconcileRedisHAProxyDeployment(cr *argoproj.ArgoCD) e if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { if !cr.Spec.HA.Enabled { // Deployment exists but HA enabled flag has been set to false, delete the Deployment + argoutil.LogResourceDeletion(log, existing, "redis ha is disabled") return r.Client.Delete(context.TODO(), existing) } changed := false + explanation := "" actualImage := existing.Spec.Template.Spec.Containers[0].Image desiredImage := getRedisHAProxyContainerImage(cr) if actualImage != desiredImage { existing.Spec.Template.Spec.Containers[0].Image = desiredImage existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + explanation = "container image" changed = true } - updateNodePlacement(existing, deploy, &changed) + updateNodePlacement(existing, deploy, &changed, &explanation) if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Resources, existing.Spec.Template.Spec.Containers[0].Resources) { existing.Spec.Template.Spec.Containers[0].Resources = deploy.Spec.Template.Spec.Containers[0].Resources + if changed { + explanation += ", " + } + explanation += "container resources" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].SecurityContext, existing.Spec.Template.Spec.Containers[0].SecurityContext) { existing.Spec.Template.Spec.Containers[0].SecurityContext = deploy.Spec.Template.Spec.Containers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.InitContainers[0].Resources, existing.Spec.Template.Spec.InitContainers[0].Resources) { existing.Spec.Template.Spec.InitContainers[0].Resources = deploy.Spec.Template.Spec.InitContainers[0].Resources + if changed { + explanation += ", " + } + explanation += "init container resources" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.InitContainers[0].SecurityContext, existing.Spec.Template.Spec.InitContainers[0].SecurityContext) { existing.Spec.Template.Spec.InitContainers[0].SecurityContext = deploy.Spec.Template.Spec.InitContainers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "init container security context" changed = true } if changed { + argoutil.LogResourceUpdate(log, existing, "updating", explanation) return r.Client.Update(context.TODO(), existing) } return nil // Deployment found, do nothing @@ -846,6 +887,7 @@ func (r *ReconcileArgoCD) reconcileRedisHAProxyDeployment(cr *argoproj.ArgoCD) e if err := controllerutil.SetControllerReference(cr, deploy, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, deploy) return r.Client.Create(context.TODO(), deploy) } @@ -1140,15 +1182,16 @@ func (r *ReconcileArgoCD) reconcileRepoDeployment(cr *argoproj.ArgoCD, useTLSFor if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { if !cr.Spec.Repo.IsEnabled() { - log.Info("Existing ArgoCD Repo Server found but should be disabled. Deleting Repo Server") // Delete existing deployment for ArgoCD Repo Server, if any .. + argoutil.LogResourceDeletion(log, existing, "repo server is disabled") return r.Client.Delete(context.TODO(), existing) } else if cr.Spec.Repo.IsRemote() { - log.Info("Repo Server remote field exists, Repo Server deployment should be disabled. Deleting Repo Server.") + argoutil.LogResourceDeletion(log, deploy, "remote repo server is configured") return r.Client.Delete(context.TODO(), deploy) } changed := false + explanation := "" actualImage := existing.Spec.Template.Spec.Containers[0].Image desiredImage := getRepoServerContainerImage(cr) if actualImage != desiredImage { @@ -1159,58 +1202,103 @@ func (r *ReconcileArgoCD) reconcileRepoDeployment(cr *argoproj.ArgoCD, useTLSFor } } existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + explanation = "container image" changed = true } - updateNodePlacement(existing, deploy, &changed) + updateNodePlacement(existing, deploy, &changed, &explanation) if !reflect.DeepEqual(deploy.Spec.Template.Spec.Volumes, existing.Spec.Template.Spec.Volumes) { existing.Spec.Template.Spec.Volumes = deploy.Spec.Template.Spec.Volumes + if changed { + explanation += ", " + } + explanation += "volumes" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].VolumeMounts, existing.Spec.Template.Spec.Containers[0].VolumeMounts) { existing.Spec.Template.Spec.Containers[0].VolumeMounts = deploy.Spec.Template.Spec.Containers[0].VolumeMounts + if changed { + explanation += ", " + } + explanation += "container volume mounts" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Env, existing.Spec.Template.Spec.Containers[0].Env) { existing.Spec.Template.Spec.Containers[0].Env = deploy.Spec.Template.Spec.Containers[0].Env + if changed { + explanation += ", " + } + explanation += "container env" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Resources, existing.Spec.Template.Spec.Containers[0].Resources) { existing.Spec.Template.Spec.Containers[0].Resources = deploy.Spec.Template.Spec.Containers[0].Resources + if changed { + explanation += ", " + } + explanation += "container resources" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Command, existing.Spec.Template.Spec.Containers[0].Command) { existing.Spec.Template.Spec.Containers[0].Command = deploy.Spec.Template.Spec.Containers[0].Command + if changed { + explanation += ", " + } + explanation += "container command" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].SecurityContext, existing.Spec.Template.Spec.Containers[0].SecurityContext) { existing.Spec.Template.Spec.Containers[0].SecurityContext = deploy.Spec.Template.Spec.Containers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[1:], existing.Spec.Template.Spec.Containers[1:]) { existing.Spec.Template.Spec.Containers = append(existing.Spec.Template.Spec.Containers[0:1], deploy.Spec.Template.Spec.Containers[1:]...) + if changed { + explanation += ", " + } + explanation += "additional containers" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.InitContainers, existing.Spec.Template.Spec.InitContainers) { existing.Spec.Template.Spec.InitContainers = deploy.Spec.Template.Spec.InitContainers + if changed { + explanation += ", " + } + explanation += "init containers" changed = true } if !reflect.DeepEqual(deploy.Spec.Replicas, existing.Spec.Replicas) { existing.Spec.Replicas = deploy.Spec.Replicas + if changed { + explanation += ", " + } + explanation += "replicas" changed = true } if deploy.Spec.Template.Spec.AutomountServiceAccountToken != existing.Spec.Template.Spec.AutomountServiceAccountToken { existing.Spec.Template.Spec.AutomountServiceAccountToken = deploy.Spec.Template.Spec.AutomountServiceAccountToken + if changed { + explanation += ", " + } + explanation += "auto-mount service account token" changed = true } if deploy.Spec.Template.Spec.ServiceAccountName != existing.Spec.Template.Spec.ServiceAccountName { existing.Spec.Template.Spec.ServiceAccountName = deploy.Spec.Template.Spec.ServiceAccountName existing.Spec.Template.Spec.DeprecatedServiceAccount = deploy.Spec.Template.Spec.ServiceAccountName + if changed { + explanation += ", " + } + explanation += "service account name" changed = true } @@ -1220,15 +1308,24 @@ func (r *ReconcileArgoCD) reconcileRepoDeployment(cr *argoproj.ArgoCD, useTLSFor if !reflect.DeepEqual(deploy.Spec.Template.Annotations, existing.Spec.Template.Annotations) { 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 changed { + explanation += ", " + } + explanation += "labels" changed = true } if changed { + argoutil.LogResourceUpdate(log, existing, "updating", explanation) return r.Client.Update(context.TODO(), existing) } return nil // Deployment found with nothing to do, move along... @@ -1247,6 +1344,7 @@ func (r *ReconcileArgoCD) reconcileRepoDeployment(cr *argoproj.ArgoCD, useTLSFor if err := controllerutil.SetControllerReference(cr, deploy, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, deploy) return r.Client.Create(context.TODO(), deploy) } @@ -1439,61 +1537,99 @@ func (r *ReconcileArgoCD) reconcileServerDeployment(cr *argoproj.ArgoCD, useTLSF existing := newDeploymentWithSuffix("server", "server", cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { if !cr.Spec.Server.IsEnabled() { - log.Info("Existing ArgoCD Server found but should be disabled. Deleting ArgoCD Server") // Delete existing deployment for ArgoCD Server, if any .. + argoutil.LogResourceDeletion(log, existing, "argocd server is disabled") return r.Client.Delete(context.TODO(), existing) } actualImage := existing.Spec.Template.Spec.Containers[0].Image desiredImage := getArgoContainerImage(cr) changed := false + explanation := "" if actualImage != desiredImage { existing.Spec.Template.Spec.Containers[0].Image = desiredImage existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + explanation = "container image" changed = true } - updateNodePlacement(existing, deploy, &changed) + updateNodePlacement(existing, deploy, &changed, &explanation) if !reflect.DeepEqual(existing.Spec.Template.Spec.Containers[0].Env, deploy.Spec.Template.Spec.Containers[0].Env) { existing.Spec.Template.Spec.Containers[0].Env = deploy.Spec.Template.Spec.Containers[0].Env + if changed { + explanation += ", " + } + explanation += "container env" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.InitContainers, existing.Spec.Template.Spec.InitContainers) { existing.Spec.Template.Spec.InitContainers = deploy.Spec.Template.Spec.InitContainers + if changed { + explanation += ", " + } + explanation += "init containers" changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.Containers[0].Command, deploy.Spec.Template.Spec.Containers[0].Command) { existing.Spec.Template.Spec.Containers[0].Command = deploy.Spec.Template.Spec.Containers[0].Command + if changed { + explanation += ", " + } + explanation += "container command" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Volumes, existing.Spec.Template.Spec.Volumes) { existing.Spec.Template.Spec.Volumes = deploy.Spec.Template.Spec.Volumes + if changed { + explanation += ", " + } + explanation += "volumes" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].VolumeMounts, existing.Spec.Template.Spec.Containers[0].VolumeMounts) { existing.Spec.Template.Spec.Containers[0].VolumeMounts = deploy.Spec.Template.Spec.Containers[0].VolumeMounts + if changed { + explanation += ", " + } + explanation += "container volume mounts" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Resources, existing.Spec.Template.Spec.Containers[0].Resources) { existing.Spec.Template.Spec.Containers[0].Resources = deploy.Spec.Template.Spec.Containers[0].Resources + if changed { + explanation += ", " + } + explanation += "container resources" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].SecurityContext, existing.Spec.Template.Spec.Containers[0].SecurityContext) { existing.Spec.Template.Spec.Containers[0].SecurityContext = deploy.Spec.Template.Spec.Containers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[1:], existing.Spec.Template.Spec.Containers[1:]) { existing.Spec.Template.Spec.Containers = append(existing.Spec.Template.Spec.Containers[0:1], deploy.Spec.Template.Spec.Containers[1:]...) + if changed { + explanation += ", " + } + explanation += "additional containers" changed = true } if !reflect.DeepEqual(deploy.Spec.Replicas, existing.Spec.Replicas) { if !cr.Spec.Server.Autoscale.Enabled { existing.Spec.Replicas = deploy.Spec.Replicas + if changed { + explanation += ", " + } + explanation += "replicas" changed = true } } @@ -1504,14 +1640,23 @@ func (r *ReconcileArgoCD) reconcileServerDeployment(cr *argoproj.ArgoCD, useTLSF if !reflect.DeepEqual(deploy.Spec.Template.Annotations, existing.Spec.Template.Annotations) { 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 changed { + explanation += ", " + } + explanation += "labels" changed = true } if changed { + argoutil.LogResourceUpdate(log, existing, "updating", explanation) return r.Client.Update(context.TODO(), existing) } return nil // Deployment found with nothing to do, move along... @@ -1525,6 +1670,7 @@ func (r *ReconcileArgoCD) reconcileServerDeployment(cr *argoproj.ArgoCD, useTLSF if err := controllerutil.SetControllerReference(cr, deploy, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, deploy) return r.Client.Create(context.TODO(), deploy) } @@ -1536,6 +1682,7 @@ func (r *ReconcileArgoCD) triggerDeploymentRollout(deployment *appsv1.Deployment } deployment.Spec.Template.ObjectMeta.Labels[key] = nowNano() + argoutil.LogResourceUpdate(log, deployment, "to trigger rollout") return r.Client.Update(context.TODO(), deployment) } @@ -1570,13 +1717,21 @@ func isRemoveManagedByLabelOnArgoCDDeletion() bool { } // to update nodeSelector and tolerations in reconciler -func updateNodePlacement(existing *appsv1.Deployment, deploy *appsv1.Deployment, changed *bool) { +func updateNodePlacement(existing *appsv1.Deployment, deploy *appsv1.Deployment, changed *bool, explanation *string) { if !reflect.DeepEqual(existing.Spec.Template.Spec.NodeSelector, deploy.Spec.Template.Spec.NodeSelector) { existing.Spec.Template.Spec.NodeSelector = deploy.Spec.Template.Spec.NodeSelector + if *changed { + *explanation += ", " + } + *explanation += "node selector" *changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.Tolerations, deploy.Spec.Template.Spec.Tolerations) { existing.Spec.Template.Spec.Tolerations = deploy.Spec.Template.Spec.Tolerations + if *changed { + *explanation += ", " + } + *explanation += "tolerations" *changed = true } } diff --git a/controllers/argocd/deployment_test.go b/controllers/argocd/deployment_test.go index 4841f7244..a3b49010f 100644 --- a/controllers/argocd/deployment_test.go +++ b/controllers/argocd/deployment_test.go @@ -1888,14 +1888,22 @@ func Test_UpdateNodePlacement(t *testing.T) { } expectedChange := false actualChange := false - updateNodePlacement(deployment, deployment, &actualChange) + explanation := "" + updateNodePlacement(deployment, deployment, &actualChange, &explanation) if actualChange != expectedChange { t.Fatalf("updateNodePlacement failed, value of changed: %t", actualChange) } - updateNodePlacement(deployment, deployment2, &actualChange) + if explanation != "" { + t.Fatalf("updateNodePlacement returned unexpected explanation: '%s'", explanation) + } + + updateNodePlacement(deployment, deployment2, &actualChange, &explanation) if actualChange == expectedChange { t.Fatalf("updateNodePlacement failed, value of changed: %t", actualChange) } + if explanation != "node selector, tolerations" { + t.Fatalf("updateNodePlacement returned unexpected explanation: '%s'", explanation) + } } func assertDeploymentHasProxyVars(t *testing.T, c client.Client, name string) { diff --git a/controllers/argocd/dex.go b/controllers/argocd/dex.go index 58e6e829c..647bab244 100644 --- a/controllers/argocd/dex.go +++ b/controllers/argocd/dex.go @@ -56,7 +56,14 @@ func (r *ReconcileArgoCD) getDexOAuthClientSecret(cr *argoproj.ArgoCD) (*string, } if tokenSecret == nil { - // This change of creating secret for dex service account,is due to change of reduction of secret-based service account tokens in k8s v1.24 so from k8s v1.24 no default secret for service account is created, but for dex to work we need to provide token of secret used by dex service account as a oauth token, this change helps to achieve it, in long run we should see do dex really requires a secret or it manages to create one using TokenRequest API or may be change how dex is used or configured by operator + // This change of creating secret for dex service account,is due to + // change of reduction of secret-based service account tokens in k8s + // v1.24 so from k8s v1.24 no default secret for service account is + // created, but for dex to work we need to provide token of secret used + // by dex service account as a oauth token, this change helps to achieve + // it, in long run we should see do dex really requires a secret or it + // manages to create one using TokenRequest API or may be change how dex + // is used or configured by operator secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "argocd-dex-server-token-", @@ -67,6 +74,7 @@ func (r *ReconcileArgoCD) getDexOAuthClientSecret(cr *argoproj.ArgoCD) (*string, }, Type: corev1.SecretTypeServiceAccountToken, } + argoutil.LogResourceCreation(log, secret) err := r.Client.Create(context.TODO(), secret) if err != nil { return nil, e.New("unable to locate and create ServiceAccount token for OAuth client secret") @@ -80,6 +88,7 @@ func (r *ReconcileArgoCD) getDexOAuthClientSecret(cr *argoproj.ArgoCD) (*string, Namespace: cr.Namespace, } sa.Secrets = append(sa.Secrets, *tokenSecret) + argoutil.LogResourceUpdate(log, sa, "adding ServiceAccount token for OAuth client secret") err = r.Client.Update(context.TODO(), sa) if err != nil { return nil, e.New("failed to add ServiceAccount token for OAuth client secret") @@ -113,6 +122,7 @@ func (r *ReconcileArgoCD) reconcileDexConfiguration(cm *corev1.ConfigMap, cr *ar if actual != desired { // Update ConfigMap with desired configuration. cm.Data[common.ArgoCDKeyDexConfig] = desired + argoutil.LogResourceUpdate(log, cm, "updating dex configuration") if err := r.Client.Update(context.TODO(), cm); err != nil { return err } @@ -125,6 +135,7 @@ func (r *ReconcileArgoCD) reconcileDexConfiguration(cm *corev1.ConfigMap, cr *ar } deploy.Spec.Template.ObjectMeta.Labels["dex.config.changed"] = time.Now().UTC().Format("01022006-150406-MST") + argoutil.LogResourceUpdate(log, deploy, "to trigger dex deployment rollout") return r.Client.Update(context.TODO(), deploy) } return nil @@ -218,6 +229,7 @@ func (r *ReconcileArgoCD) reconcileDexServiceAccount(cr *argoproj.ArgoCD) error ann[common.ArgoCDKeyDexOAuthRedirectURI] = uri sa.ObjectMeta.Annotations = ann + argoutil.LogResourceUpdate(log, sa, "updating redirect uri") return r.Client.Update(context.TODO(), sa) } @@ -324,16 +336,18 @@ func (r *ReconcileArgoCD) reconcileDexDeployment(cr *argoproj.ArgoCD) error { // dex uninstallation requested if !UseDex(cr) { - log.Info("deleting the existing dex deployment because dex uninstallation has been requested") + argoutil.LogResourceDeletion(log, existing, "dex uninstallation has been requested") return r.Client.Delete(context.TODO(), existing) } changed := false + explanation := "" actualImage := existing.Spec.Template.Spec.Containers[0].Image desiredImage := getDexContainerImage(cr) if actualImage != desiredImage { existing.Spec.Template.Spec.Containers[0].Image = desiredImage existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + explanation = "container image" changed = true } @@ -342,37 +356,62 @@ func (r *ReconcileArgoCD) reconcileDexDeployment(cr *argoproj.ArgoCD) error { if actualImage != desiredImage { existing.Spec.Template.Spec.InitContainers[0].Image = desiredImage existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + if changed { + explanation += ", " + } + explanation += "init container image" changed = true } - updateNodePlacement(existing, deploy, &changed) + updateNodePlacement(existing, deploy, &changed, &explanation) if !reflect.DeepEqual(existing.Spec.Template.Spec.Containers[0].Env, deploy.Spec.Template.Spec.Containers[0].Env) { existing.Spec.Template.Spec.Containers[0].Env = deploy.Spec.Template.Spec.Containers[0].Env + if changed { + explanation += ", " + } + explanation += "container env" changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.InitContainers[0].Env, deploy.Spec.Template.Spec.InitContainers[0].Env) { existing.Spec.Template.Spec.InitContainers[0].Env = deploy.Spec.Template.Spec.InitContainers[0].Env + if changed { + explanation += ", " + } + explanation += "init container env" changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.InitContainers[0].SecurityContext, deploy.Spec.Template.Spec.InitContainers[0].SecurityContext) { existing.Spec.Template.Spec.InitContainers[0].SecurityContext = deploy.Spec.Template.Spec.InitContainers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "init container security context" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].Resources, existing.Spec.Template.Spec.Containers[0].Resources) { existing.Spec.Template.Spec.Containers[0].Resources = deploy.Spec.Template.Spec.Containers[0].Resources + if changed { + explanation += ", " + } + explanation += "container resources" changed = true } if !reflect.DeepEqual(deploy.Spec.Template.Spec.Containers[0].SecurityContext, existing.Spec.Template.Spec.Containers[0].SecurityContext) { existing.Spec.Template.Spec.Containers[0].SecurityContext = deploy.Spec.Template.Spec.Containers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if changed { + argoutil.LogResourceUpdate(log, existing, "updating", explanation) return r.Client.Update(context.TODO(), existing) } return nil // Deployment found with nothing to do, move along... @@ -387,7 +426,7 @@ func (r *ReconcileArgoCD) reconcileDexDeployment(cr *argoproj.ArgoCD) error { return err } - log.Info(fmt.Sprintf("creating deployment %s for Argo CD instance %s in namespace %s", deploy.Name, cr.Name, cr.Namespace)) + argoutil.LogResourceCreation(log, deploy) return r.Client.Create(context.TODO(), deploy) } @@ -398,7 +437,7 @@ func (r *ReconcileArgoCD) reconcileDexService(cr *argoproj.ArgoCD) error { // dex uninstallation requested if !UseDex(cr) { - log.Info("deleting the existing Dex service because dex uninstallation has been requested") + argoutil.LogResourceDeletion(log, svc, "dex uninstallation has been requested") return r.Client.Delete(context.TODO(), svc) } return nil @@ -431,7 +470,7 @@ func (r *ReconcileArgoCD) reconcileDexService(cr *argoproj.ArgoCD) error { return err } - log.Info(fmt.Sprintf("creating service %s for Argo CD instance %s in namespace %s", svc.Name, cr.Name, cr.Namespace)) + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } diff --git a/controllers/argocd/hpa.go b/controllers/argocd/hpa.go index f55e6324c..7d1f5dba5 100644 --- a/controllers/argocd/hpa.go +++ b/controllers/argocd/hpa.go @@ -75,6 +75,7 @@ func (r *ReconcileArgoCD) reconcileServerHPA(cr *argoproj.ArgoCD) error { existingHPA := newHorizontalPodAutoscalerWithSuffix("server", cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, existingHPA.Name, existingHPA) { if !cr.Spec.Server.Autoscale.Enabled { + argoutil.LogResourceDeletion(log, existingHPA, "server autoscaling is disabled") return r.Client.Delete(context.TODO(), existingHPA) // HorizontalPodAutoscaler found but globally disabled, delete it. } @@ -88,6 +89,7 @@ func (r *ReconcileArgoCD) reconcileServerHPA(cr *argoproj.ArgoCD) error { } if changed { + argoutil.LogResourceUpdate(log, existingHPA, "due to differences from ArgoCD CR") return r.Client.Update(context.TODO(), existingHPA) } @@ -104,6 +106,7 @@ func (r *ReconcileArgoCD) reconcileServerHPA(cr *argoproj.ArgoCD) error { defaultHPA.Spec = *cr.Spec.Server.Autoscale.HPA } + argoutil.LogResourceCreation(log, defaultHPA) return r.Client.Create(context.TODO(), defaultHPA) } diff --git a/controllers/argocd/ingress.go b/controllers/argocd/ingress.go index 593e9846c..f9137df1e 100644 --- a/controllers/argocd/ingress.go +++ b/controllers/argocd/ingress.go @@ -99,6 +99,7 @@ func (r *ReconcileArgoCD) reconcileArgoServerIngress(cr *argoproj.ArgoCD) error if !cr.Spec.Server.Ingress.Enabled { if objectFound { // Ingress exists but enabled flag has been set to false, delete the Ingress + argoutil.LogResourceDeletion(log, ingress, "server ingress is disabled") return r.Client.Delete(context.TODO(), ingress) } return nil // Ingress not enabled, move along... @@ -160,24 +161,39 @@ func (r *ReconcileArgoCD) reconcileArgoServerIngress(cr *argoproj.ArgoCD) error } if objectFound { changed := false + explanation := "" // If Ingress found and enabled, make sure the ingressClassName is up-to-date if existingIngress.Spec.IngressClassName != cr.Spec.Server.Ingress.IngressClassName { - changed = true existingIngress.Spec.IngressClassName = cr.Spec.Server.Ingress.IngressClassName + explanation = "ingress class name" + changed = true } if !reflect.DeepEqual(cr.Spec.Server.Ingress.Annotations, existingIngress.ObjectMeta.Annotations) { - changed = true existingIngress.ObjectMeta.Annotations = cr.Spec.Server.Ingress.Annotations + if changed { + explanation += ", " + } + explanation += "annotations" + changed = true } if !reflect.DeepEqual(ingress.Spec.Rules, existingIngress.Spec.Rules) { - changed = true existingIngress.Spec.Rules = ingress.Spec.Rules + if changed { + explanation += ", " + } + explanation += "ingress rules" + changed = true } if !reflect.DeepEqual(ingress.Spec.TLS, existingIngress.Spec.TLS) { - changed = true existingIngress.Spec.TLS = ingress.Spec.TLS + if changed { + explanation += ", " + } + explanation += "ingress tls" + changed = true } if changed { + argoutil.LogResourceUpdate(log, existingIngress, "updating", explanation) return r.Client.Update(context.TODO(), existingIngress) } return nil // Ingress with no changes to apply, do nothing @@ -185,6 +201,7 @@ func (r *ReconcileArgoCD) reconcileArgoServerIngress(cr *argoproj.ArgoCD) error if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, ingress) return r.Client.Create(context.TODO(), ingress) } @@ -194,6 +211,7 @@ func (r *ReconcileArgoCD) reconcileArgoServerGRPCIngress(cr *argoproj.ArgoCD) er if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { if !cr.Spec.Server.GRPC.Ingress.Enabled { // Ingress exists but enabled flag has been set to false, delete the Ingress + argoutil.LogResourceDeletion(log, ingress, "server grpc ingress is disabled") return r.Client.Delete(context.TODO(), ingress) } return nil // Ingress found and enabled, do nothing @@ -260,6 +278,7 @@ func (r *ReconcileArgoCD) reconcileArgoServerGRPCIngress(cr *argoproj.ArgoCD) er if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, ingress) return r.Client.Create(context.TODO(), ingress) } @@ -270,6 +289,13 @@ func (r *ReconcileArgoCD) reconcileGrafanaIngress(cr *argoproj.ArgoCD) error { //nolint:staticcheck if !cr.Spec.Grafana.Enabled || !cr.Spec.Grafana.Ingress.Enabled { // Ingress exists but enabled flag has been set to false, delete the Ingress + var explanation string + if !cr.Spec.Grafana.Enabled { + explanation = "grafana is disabled" + } else { + explanation = "grafana ingress is disabled" + } + argoutil.LogResourceDeletion(log, ingress, explanation) return r.Client.Delete(context.TODO(), ingress) } log.Info(grafanaDeprecatedWarning) @@ -292,6 +318,13 @@ func (r *ReconcileArgoCD) reconcilePrometheusIngress(cr *argoproj.ArgoCD) error if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { if !cr.Spec.Prometheus.Enabled || !cr.Spec.Prometheus.Ingress.Enabled { // Ingress exists but enabled flag has been set to false, delete the Ingress + var explanation string + if !cr.Spec.Prometheus.Enabled { + explanation = "prometheus is disabled" + } else { + explanation = "prometheus ingress is disabled" + } + argoutil.LogResourceDeletion(log, ingress, explanation) return r.Client.Delete(context.TODO(), ingress) } return nil // Ingress found and enabled, do nothing @@ -357,6 +390,7 @@ func (r *ReconcileArgoCD) reconcilePrometheusIngress(cr *argoproj.ArgoCD) error if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, ingress) return r.Client.Create(context.TODO(), ingress) } @@ -365,13 +399,20 @@ func (r *ReconcileArgoCD) reconcileApplicationSetControllerIngress(cr *argoproj. ingress := newIngressWithSuffix(common.ApplicationSetServiceNameSuffix, cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Ingress.Enabled { + var explanation string + if cr.Spec.ApplicationSet == nil { + explanation = "applicationset is disabled" + } else { + explanation = "applicationset webhook ingress is disabled" + } + argoutil.LogResourceDeletion(log, ingress, explanation) return r.Client.Delete(context.TODO(), ingress) } return nil // Ingress found and enabled, do nothing } if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Ingress.Enabled { - log.Info("not enabled") + log.Info("applicationset or applicationset webhook ingress disabled") return nil // Ingress not enabled, move along... } @@ -426,5 +467,6 @@ func (r *ReconcileArgoCD) reconcileApplicationSetControllerIngress(cr *argoproj. if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, ingress) return r.Client.Create(context.TODO(), ingress) } diff --git a/controllers/argocd/keycloak.go b/controllers/argocd/keycloak.go index c647453ad..cd8c4d77f 100644 --- a/controllers/argocd/keycloak.go +++ b/controllers/argocd/keycloak.go @@ -658,6 +658,7 @@ func (r *ReconcileArgoCD) newKeycloakInstance(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, ing, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, ing) err = r.Client.Create(context.TODO(), ing) if err != nil { return err @@ -677,6 +678,7 @@ func (r *ReconcileArgoCD) newKeycloakInstance(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) err = r.Client.Create(context.TODO(), svc) if err != nil { return err @@ -696,6 +698,7 @@ func (r *ReconcileArgoCD) newKeycloakInstance(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, dep, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, dep) err = r.Client.Create(context.TODO(), dep) if err != nil { return err @@ -1001,6 +1004,7 @@ func (r *ReconcileArgoCD) updateArgoCDConfiguration(cr *argoproj.ArgoCD, kRouteU } argoCDSecret.Data["oidc.keycloak.clientSecret"] = []byte(oAuthClientSecret) + argoutil.LogResourceUpdate(log, argoCDSecret, "updating client secret for keycloak oidc") err = r.Client.Update(context.TODO(), argoCDSecret) if err != nil { log.Error(err, fmt.Sprintf("Error updating ArgoCD Secret for ArgoCD %s in namespace %s", @@ -1033,6 +1037,7 @@ func (r *ReconcileArgoCD) updateArgoCDConfiguration(cr *argoproj.ArgoCD, kRouteU err = r.Client.Get(context.TODO(), types.NamespacedName{Name: oAuthClient.Name}, oAuthClient) if err != nil { if errors.IsNotFound(err) { + argoutil.LogResourceCreation(log, oAuthClient) err = r.Client.Create(context.TODO(), oAuthClient) if err != nil { return err @@ -1070,6 +1075,7 @@ func (r *ReconcileArgoCD) updateArgoCDConfiguration(cr *argoproj.ArgoCD, kRouteU } argoCDCM.Data[common.ArgoCDKeyOIDCConfig] = string(o) + argoutil.LogResourceUpdate(log, argoCDCM, "updating oidc config with keycloak realm") err = r.Client.Update(context.TODO(), argoCDCM) if err != nil { log.Error(err, fmt.Sprintf("Error updating OIDC Configuration for ArgoCD %s in namespace %s", @@ -1088,6 +1094,7 @@ func (r *ReconcileArgoCD) updateArgoCDConfiguration(cr *argoproj.ArgoCD, kRouteU } argoRBACCM.Data["scopes"] = "[groups,email]" + argoutil.LogResourceUpdate(log, argoRBACCM, "updating rbac scopes for keycloak") err = r.Client.Update(context.TODO(), argoRBACCM) if err != nil { log.Error(err, fmt.Sprintf("Error updating ArgoCD RBAC configmap %s in namespace %s", @@ -1114,12 +1121,11 @@ func handleKeycloakPodDeletion(dc *appsv1.DeploymentConfig) error { return err } - log.Info("Set the Realm Creation status annoation to false") existingDC, err := dcClient.DeploymentConfigs(dc.Namespace).Get(context.TODO(), defaultKeycloakIdentifier, metav1.GetOptions{}) if err != nil { return err } - + argoutil.LogResourceUpdate(log, existingDC, "setting the realm created status annotation to false") existingDC.Annotations["argocd.argoproj.io/realm-created"] = "false" _, err = dcClient.DeploymentConfigs(dc.Namespace).Update(context.TODO(), existingDC, metav1.UpdateOptions{}) if err != nil { @@ -1311,6 +1317,7 @@ func (r *ReconcileArgoCD) reconcileKeycloakForOpenShift(cr *argoproj.ArgoCD) err return err } + argoutil.LogResourceCreation(log, templateInstanceRef) err = r.Client.Create(context.TODO(), templateInstanceRef) if err != nil { return err @@ -1332,21 +1339,28 @@ func (r *ReconcileArgoCD) reconcileKeycloakForOpenShift(cr *argoproj.ArgoCD) err cr.Name, cr.Namespace)) } else { changed := false + explanation := "" // Handle Image upgrades desiredImage := getKeycloakContainerImage(cr) if existingDC.Spec.Template.Spec.Containers[0].Image != desiredImage { existingDC.Spec.Template.Spec.Containers[0].Image = desiredImage + explanation = "container image" changed = true } desiredSecurityContext := restrictedContainerSecurityContext() if !reflect.DeepEqual(existingDC.Spec.Template.Spec.Containers[0].SecurityContext, desiredSecurityContext) { existingDC.Spec.Template.Spec.Containers[0].SecurityContext = desiredSecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if changed { err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + argoutil.LogResourceUpdate(log, existingDC, "updating", explanation) return r.Client.Update(context.TODO(), existingDC) }) @@ -1399,6 +1413,7 @@ func (r *ReconcileArgoCD) reconcileKeycloakForOpenShift(cr *argoproj.ArgoCD) err existingDC.Annotations["argocd.argoproj.io/realm-created"] = "true" err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + argoutil.LogResourceUpdate(log, existingDC, "setting the realm created status annotation to true") return r.Client.Update(context.TODO(), existingDC) }) @@ -1445,21 +1460,28 @@ func (r *ReconcileArgoCD) reconcileKeycloak(cr *argoproj.ArgoCD) error { cr.Name, cr.Namespace)) } else { changed := false + explanation := "" // Handle Image upgrades desiredImage := getKeycloakContainerImage(cr) if existingDeployment.Spec.Template.Spec.Containers[0].Image != desiredImage { existingDeployment.Spec.Template.Spec.Containers[0].Image = desiredImage + explanation = "container image" changed = true } desiredSecurityContext := restrictedContainerSecurityContext() if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].SecurityContext, desiredSecurityContext) { existingDeployment.Spec.Template.Spec.Containers[0].SecurityContext = desiredSecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if changed { err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { + argoutil.LogResourceUpdate(log, existingDeployment, "updating", explanation) return r.Client.Update(context.TODO(), existingDeployment) }) @@ -1495,6 +1517,7 @@ func (r *ReconcileArgoCD) reconcileKeycloak(cr *argoproj.ArgoCD) error { // Update Realm creation. This will avoid posting of realm configuration on further reconciliations. existingDeployment.Annotations["argocd.argoproj.io/realm-created"] = "true" + argoutil.LogResourceUpdate(log, existingDeployment, "setting the realm created status annotation to true") err = r.Client.Update(context.TODO(), existingDeployment) if err != nil { return err diff --git a/controllers/argocd/networkpolicies.go b/controllers/argocd/networkpolicies.go index 7ea323af9..311b612f1 100644 --- a/controllers/argocd/networkpolicies.go +++ b/controllers/argocd/networkpolicies.go @@ -108,21 +108,31 @@ func (r *ReconcileArgoCD) ReconcileRedisNetworkPolicy(cr *argoproj.ArgoCD) error if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { modified := false + explanation := "" if !reflect.DeepEqual(existing.Spec.PodSelector, networkPolicy.Spec.PodSelector) { existing.Spec.PodSelector = networkPolicy.Spec.PodSelector + explanation = "pod selector" modified = true } if !reflect.DeepEqual(existing.Spec.PolicyTypes, networkPolicy.Spec.PolicyTypes) { existing.Spec.PolicyTypes = networkPolicy.Spec.PolicyTypes + if modified { + explanation += ", " + } + explanation += "policy types" modified = true } if !reflect.DeepEqual(existing.Spec.Ingress, networkPolicy.Spec.Ingress) { existing.Spec.Ingress = networkPolicy.Spec.Ingress + if modified { + explanation += ", " + } + explanation += "ingress rules" modified = true } if modified { - log.Info("Updating redis network policy", "namespace", networkPolicy.Namespace, "name", networkPolicy.Name) + argoutil.LogResourceUpdate(log, existing, "updating", explanation) err := r.Client.Update(context.TODO(), existing) if err != nil { log.Error(err, "Failed to update redis network policy") @@ -141,7 +151,7 @@ func (r *ReconcileArgoCD) ReconcileRedisNetworkPolicy(cr *argoproj.ArgoCD) error return err } - log.Info("Creating redis network policy", "namespace", networkPolicy.Namespace, "name", networkPolicy.Name) + argoutil.LogResourceCreation(log, networkPolicy) err := r.Client.Create(context.TODO(), networkPolicy) if err != nil { log.Error(err, "Failed to create redis network policy") @@ -220,21 +230,31 @@ func (r *ReconcileArgoCD) ReconcileRedisHANetworkPolicy(cr *argoproj.ArgoCD) err if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { modified := false + explanation := "" if !reflect.DeepEqual(existing.Spec.PodSelector, networkPolicy.Spec.PodSelector) { existing.Spec.PodSelector = networkPolicy.Spec.PodSelector + explanation = "pod selector" modified = true } if !reflect.DeepEqual(existing.Spec.PolicyTypes, networkPolicy.Spec.PolicyTypes) { existing.Spec.PolicyTypes = networkPolicy.Spec.PolicyTypes + if modified { + explanation += ", " + } + explanation += "policy types" modified = true } if !reflect.DeepEqual(existing.Spec.Ingress, networkPolicy.Spec.Ingress) { existing.Spec.Ingress = networkPolicy.Spec.Ingress + if modified { + explanation += ", " + } + explanation += "ingress rules" modified = true } if modified { - log.Info("Updating redis ha network policy", "namespace", networkPolicy.Namespace, "name", networkPolicy.Name) + argoutil.LogResourceUpdate(log, existing, "updating", explanation) err := r.Client.Update(context.TODO(), existing) if err != nil { log.Error(err, "Failed to update redis ha network policy") @@ -253,7 +273,7 @@ func (r *ReconcileArgoCD) ReconcileRedisHANetworkPolicy(cr *argoproj.ArgoCD) err return err } - log.Info("Creating redis ha network policy", "namespace", networkPolicy.Namespace, "name", networkPolicy.Name) + argoutil.LogResourceCreation(log, networkPolicy) err := r.Client.Create(context.TODO(), networkPolicy) if err != nil { log.Error(err, "Failed to create redis ha network policy") diff --git a/controllers/argocd/notifications.go b/controllers/argocd/notifications.go index 174315e06..2150e63dd 100644 --- a/controllers/argocd/notifications.go +++ b/controllers/argocd/notifications.go @@ -90,7 +90,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsConfigurationCR(cr *argoproj.Arg } if !cr.Spec.Notifications.Enabled { - log.Info("Deleting NotificationsConfiguration as notifications is disabled") + argoutil.LogResourceDeletion(log, defaultNotificationsConfigurationCR, "notifications are disabled") return r.Client.Delete(context.TODO(), defaultNotificationsConfigurationCR) } @@ -107,6 +107,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsConfigurationCR(cr *argoproj.Arg return nil } + argoutil.LogResourceCreation(log, defaultNotificationsConfigurationCR) err := r.Client.Create(context.TODO(), defaultNotificationsConfigurationCR) if err != nil { return err @@ -202,7 +203,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsServiceAccount(cr *argoproj.Argo return nil, err } - log.Info(fmt.Sprintf("Creating serviceaccount %s", sa.Name)) + argoutil.LogResourceCreation(log, sa) err := r.Client.Create(context.TODO(), sa) if err != nil { return nil, err @@ -211,7 +212,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsServiceAccount(cr *argoproj.Argo // SA exists but shouldn't, so it should be deleted if !cr.Spec.Notifications.Enabled { - log.Info(fmt.Sprintf("Deleting serviceaccount %s as notifications is disabled", sa.Name)) + argoutil.LogResourceDeletion(log, sa, "notifications are disabled") return nil, r.Client.Delete(context.TODO(), sa) } @@ -239,7 +240,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsRole(cr *argoproj.ArgoCD) (*rbac return nil, err } - log.Info(fmt.Sprintf("Creating role %s", desiredRole.Name)) + argoutil.LogResourceCreation(log, desiredRole) err := r.Client.Create(context.TODO(), desiredRole) if err != nil { return nil, err @@ -249,7 +250,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsRole(cr *argoproj.ArgoCD) (*rbac // role exists but shouldn't, so it should be deleted if !cr.Spec.Notifications.Enabled { - log.Info(fmt.Sprintf("Deleting role %s as notifications is disabled", existingRole.Name)) + argoutil.LogResourceDeletion(log, existingRole, "notifications are disabled") return nil, r.Client.Delete(context.TODO(), existingRole) } @@ -259,6 +260,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsRole(cr *argoproj.ArgoCD) (*rbac if err := controllerutil.SetControllerReference(cr, existingRole, r.Scheme); err != nil { return nil, err } + argoutil.LogResourceUpdate(log, existingRole, "updating policy rules") return existingRole, r.Client.Update(context.TODO(), existingRole) } @@ -299,19 +301,20 @@ func (r *ReconcileArgoCD) reconcileNotificationsRoleBinding(cr *argoproj.ArgoCD, return err } - log.Info(fmt.Sprintf("Creating roleBinding %s", desiredRoleBinding.Name)) + argoutil.LogResourceCreation(log, desiredRoleBinding) return r.Client.Create(context.TODO(), desiredRoleBinding) } // roleBinding exists but shouldn't, so it should be deleted if !cr.Spec.Notifications.Enabled { - log.Info(fmt.Sprintf("Deleting roleBinding %s as notifications is disabled", existingRoleBinding.Name)) + argoutil.LogResourceDeletion(log, existingRoleBinding, "notifications are disabled") return r.Client.Delete(context.TODO(), existingRoleBinding) } // roleBinding exists and should. Reconcile roleBinding if changed if !reflect.DeepEqual(existingRoleBinding.RoleRef, desiredRoleBinding.RoleRef) { // if the RoleRef changes, delete the existing role binding and create a new one + argoutil.LogResourceDeletion(log, existingRoleBinding, "roleref changed, deleting rolebinding in order to recreate it") if err := r.Client.Delete(context.TODO(), existingRoleBinding); err != nil { return err } @@ -320,6 +323,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsRoleBinding(cr *argoproj.ArgoCD, if err := controllerutil.SetControllerReference(cr, existingRoleBinding, r.Scheme); err != nil { return err } + argoutil.LogResourceUpdate(log, existingRoleBinding, "updating subjects") return r.Client.Update(context.TODO(), existingRoleBinding) } @@ -412,6 +416,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsDeployment(cr *argoproj.ArgoCD, // fetch existing deployment by name deploymentChanged := false + explanation := "" existingDeployment := &appsv1.Deployment{} if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: desiredDeployment.Name, Namespace: cr.Namespace}, existingDeployment); err != nil { if !errors.IsNotFound(err) { @@ -428,82 +433,131 @@ func (r *ReconcileArgoCD) reconcileNotificationsDeployment(cr *argoproj.ArgoCD, return err } - log.Info(fmt.Sprintf("Creating deployment %s", desiredDeployment.Name)) + argoutil.LogResourceCreation(log, desiredDeployment) return r.Client.Create(context.TODO(), desiredDeployment) } // deployment exists but shouldn't, so it should be deleted if !cr.Spec.Notifications.Enabled { - log.Info(fmt.Sprintf("Deleting deployment %s as notifications is disabled", existingDeployment.Name)) + argoutil.LogResourceDeletion(log, existingDeployment, "notifications are disabled") return r.Client.Delete(context.TODO(), existingDeployment) } // deployment exists and should. Reconcile deployment if changed - updateNodePlacement(existingDeployment, desiredDeployment, &deploymentChanged) + updateNodePlacement(existingDeployment, desiredDeployment, &deploymentChanged, &explanation) if existingDeployment.Spec.Template.Spec.Containers[0].Image != desiredDeployment.Spec.Template.Spec.Containers[0].Image { existingDeployment.Spec.Template.Spec.Containers[0].Image = desiredDeployment.Spec.Template.Spec.Containers[0].Image existingDeployment.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + if deploymentChanged { + explanation = ", " + } + explanation += "container image" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].Command, desiredDeployment.Spec.Template.Spec.Containers[0].Command) { existingDeployment.Spec.Template.Spec.Containers[0].Command = desiredDeployment.Spec.Template.Spec.Containers[0].Command + if deploymentChanged { + explanation = ", " + } + explanation += "container command" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].Env, desiredDeployment.Spec.Template.Spec.Containers[0].Env) { existingDeployment.Spec.Template.Spec.Containers[0].Env = desiredDeployment.Spec.Template.Spec.Containers[0].Env + if deploymentChanged { + explanation = ", " + } + explanation += "container env" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Volumes, desiredDeployment.Spec.Template.Spec.Volumes) { existingDeployment.Spec.Template.Spec.Volumes = desiredDeployment.Spec.Template.Spec.Volumes + if deploymentChanged { + explanation = ", " + } + explanation += "volumes" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Replicas, desiredDeployment.Spec.Replicas) { existingDeployment.Spec.Replicas = desiredDeployment.Spec.Replicas + if deploymentChanged { + explanation = ", " + } + explanation += "replicas" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].VolumeMounts, desiredDeployment.Spec.Template.Spec.Containers[0].VolumeMounts) { existingDeployment.Spec.Template.Spec.Containers[0].VolumeMounts = desiredDeployment.Spec.Template.Spec.Containers[0].VolumeMounts + if deploymentChanged { + explanation = ", " + } + explanation += "container volume mounts" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].Resources, desiredDeployment.Spec.Template.Spec.Containers[0].Resources) { existingDeployment.Spec.Template.Spec.Containers[0].Resources = desiredDeployment.Spec.Template.Spec.Containers[0].Resources + if deploymentChanged { + explanation = ", " + } + explanation += "container resources" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.Containers[0].SecurityContext, desiredDeployment.Spec.Template.Spec.Containers[0].SecurityContext) { existingDeployment.Spec.Template.Spec.Containers[0].SecurityContext = desiredDeployment.Spec.Template.Spec.Containers[0].SecurityContext + if deploymentChanged { + explanation = ", " + } + explanation += "container security context" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Template.Spec.ServiceAccountName, desiredDeployment.Spec.Template.Spec.ServiceAccountName) { existingDeployment.Spec.Template.Spec.ServiceAccountName = desiredDeployment.Spec.Template.Spec.ServiceAccountName + if deploymentChanged { + explanation = ", " + } + explanation += "service account name" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Labels, desiredDeployment.Labels) { 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 deploymentChanged { + explanation = ", " + } + explanation += "pod labels" deploymentChanged = true } if !reflect.DeepEqual(existingDeployment.Spec.Selector, desiredDeployment.Spec.Selector) { existingDeployment.Spec.Selector = desiredDeployment.Spec.Selector + if deploymentChanged { + explanation = ", " + } + explanation += "selector" deploymentChanged = true } if deploymentChanged { + argoutil.LogResourceUpdate(log, existingDeployment, "updating", explanation) return r.Client.Update(context.TODO(), existingDeployment) } @@ -539,6 +593,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsMetricsService(cr *argoproj.Argo if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -566,6 +621,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsServiceMonitor(cr *argoproj.Argo }, } + argoutil.LogResourceCreation(log, serviceMonitor) return r.Client.Create(context.TODO(), serviceMonitor) } @@ -587,7 +643,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsSecret(cr *argoproj.ArgoCD) erro if secretExists { // secret exists but shouldn't, so it should be deleted if !cr.Spec.Notifications.Enabled { - log.Info(fmt.Sprintf("Deleting secret %s as notifications is disabled", existingSecret.Name)) + argoutil.LogResourceDeletion(log, existingSecret, "notifications are disabled") return r.Client.Delete(context.TODO(), existingSecret) } @@ -605,7 +661,7 @@ func (r *ReconcileArgoCD) reconcileNotificationsSecret(cr *argoproj.ArgoCD) erro return err } - log.Info(fmt.Sprintf("Creating secret %s", desiredSecret.Name)) + argoutil.LogResourceCreation(log, desiredSecret) err := r.Client.Create(context.TODO(), desiredSecret) if err != nil { return err diff --git a/controllers/argocd/prometheus.go b/controllers/argocd/prometheus.go index 9f7e2fe36..e9e2837ea 100644 --- a/controllers/argocd/prometheus.go +++ b/controllers/argocd/prometheus.go @@ -130,6 +130,7 @@ func (r *ReconcileArgoCD) reconcileMetricsServiceMonitor(cr *argoproj.ArgoCD) er if argoutil.IsObjectFound(r.Client, cr.Namespace, sm.Name, sm) { if !cr.Spec.Prometheus.Enabled { // ServiceMonitor exists but enabled flag has been set to false, delete the ServiceMonitor + argoutil.LogResourceDeletion(log, sm, "prometheus is disabled") return r.Client.Delete(context.TODO(), sm) } return nil // ServiceMonitor found, do nothing @@ -153,6 +154,7 @@ func (r *ReconcileArgoCD) reconcileMetricsServiceMonitor(cr *argoproj.ArgoCD) er if err := controllerutil.SetControllerReference(cr, sm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, sm) return r.Client.Create(context.TODO(), sm) } @@ -162,10 +164,12 @@ func (r *ReconcileArgoCD) reconcilePrometheus(cr *argoproj.ArgoCD) error { if argoutil.IsObjectFound(r.Client, cr.Namespace, prometheus.Name, prometheus) { if !cr.Spec.Prometheus.Enabled { // Prometheus exists but enabled flag has been set to false, delete the Prometheus + argoutil.LogResourceDeletion(log, prometheus, "prometheus is disabled") return r.Client.Delete(context.TODO(), prometheus) } if hasPrometheusSpecChanged(prometheus, cr) { prometheus.Spec.Replicas = cr.Spec.Prometheus.Size + argoutil.LogResourceUpdate(log, prometheus, "updating replica count") return r.Client.Update(context.TODO(), prometheus) } return nil // Prometheus found, do nothing @@ -182,6 +186,7 @@ func (r *ReconcileArgoCD) reconcilePrometheus(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, prometheus, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, prometheus) return r.Client.Create(context.TODO(), prometheus) } @@ -191,6 +196,7 @@ func (r *ReconcileArgoCD) reconcileRepoServerServiceMonitor(cr *argoproj.ArgoCD) if argoutil.IsObjectFound(r.Client, cr.Namespace, sm.Name, sm) { if !cr.Spec.Prometheus.Enabled { // ServiceMonitor exists but enabled flag has been set to false, delete the ServiceMonitor + argoutil.LogResourceDeletion(log, sm, "prometheus is disabled") return r.Client.Delete(context.TODO(), sm) } return nil // ServiceMonitor found, do nothing @@ -214,6 +220,7 @@ func (r *ReconcileArgoCD) reconcileRepoServerServiceMonitor(cr *argoproj.ArgoCD) if err := controllerutil.SetControllerReference(cr, sm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, sm) return r.Client.Create(context.TODO(), sm) } @@ -223,6 +230,7 @@ func (r *ReconcileArgoCD) reconcileServerMetricsServiceMonitor(cr *argoproj.Argo if argoutil.IsObjectFound(r.Client, cr.Namespace, sm.Name, sm) { if !cr.Spec.Prometheus.Enabled { // ServiceMonitor exists but enabled flag has been set to false, delete the ServiceMonitor + argoutil.LogResourceDeletion(log, sm, "prometheus is disabled") return r.Client.Delete(context.TODO(), sm) } return nil // ServiceMonitor found, do nothing @@ -246,6 +254,7 @@ func (r *ReconcileArgoCD) reconcileServerMetricsServiceMonitor(cr *argoproj.Argo if err := controllerutil.SetControllerReference(cr, sm, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, sm) return r.Client.Create(context.TODO(), sm) } @@ -259,6 +268,7 @@ func (r *ReconcileArgoCD) reconcilePrometheusRule(cr *argoproj.ArgoCD) error { if !cr.Spec.Monitoring.Enabled { // PrometheusRule exists but enabled flag has been set to false, delete the PrometheusRule log.Info("instance monitoring disabled, deleting component status tracking prometheusRule") + argoutil.LogResourceDeletion(log, promRule, "instance monitoring is disabled") return r.Client.Delete(context.TODO(), promRule) } return nil // PrometheusRule found, do nothing @@ -379,7 +389,7 @@ func (r *ReconcileArgoCD) reconcilePrometheusRule(cr *argoproj.ArgoCD) error { return err } - log.Info("instance monitoring enabled, creating component status tracking prometheusRule") + argoutil.LogResourceCreation(log, promRule, "for component status tracking, since instance monitoring is enabled") return r.Client.Create(context.TODO(), promRule) // Create PrometheusRule } diff --git a/controllers/argocd/role.go b/controllers/argocd/role.go index 3e1a22bd2..95ce99b3d 100644 --- a/controllers/argocd/role.go +++ b/controllers/argocd/role.go @@ -109,6 +109,7 @@ func (r *ReconcileArgoCD) reconcileRole(name string, policyRules []v1.PolicyRule if namespace.DeletionTimestamp != nil { if _, ok := namespace.Labels[common.ArgoCDManagedByLabel]; ok { delete(namespace.Labels, common.ArgoCDManagedByLabel) + argoutil.LogResourceUpdate(log, &namespace, "namespace is terminating, removing 'managed-by' label") _ = r.Client.Update(context.TODO(), &namespace) } continue @@ -156,13 +157,26 @@ func (r *ReconcileArgoCD) reconcileRole(name string, policyRules []v1.PolicyRule } } - log.Info(fmt.Sprintf("creating role %s for Argo CD instance %s in namespace %s", role.Name, cr.Name, cr.Namespace)) + argoutil.LogResourceCreation(log, role) if err := r.Client.Create(context.TODO(), role); err != nil { return nil, err } continue } else { - if !UseApplicationController(name, cr) || !UseRedis(name, cr) || !UseServer(name, cr) { + shouldDelete := false + explanation := "" + if !UseApplicationController(name, cr) { + shouldDelete = true + explanation = "application controller is disabled" + } else if !UseRedis(name, cr) { + shouldDelete = true + explanation = "redis is disabled" + } else if !UseServer(name, cr) { + shouldDelete = true + explanation = "server is disabled" + } + if shouldDelete { + argoutil.LogResourceDeletion(log, role, explanation) if err := r.Client.Delete(context.TODO(), role); err != nil { return nil, err } @@ -174,7 +188,13 @@ func (r *ReconcileArgoCD) reconcileRole(name string, policyRules []v1.PolicyRule if customRole != "" || (name == common.ArgoCDDexServerComponent && !UseDex(cr)) { - log.Info("deleting the existing Dex role because dex is not configured") + var explanation string + if customRole != "" { + explanation = "custom cluster role is provided" + } else { + explanation = "dex is disabled or not configured" + } + argoutil.LogResourceDeletion(log, &existingRole, explanation) if err := r.Client.Delete(context.TODO(), &existingRole); err != nil { return nil, err } @@ -184,6 +204,7 @@ func (r *ReconcileArgoCD) reconcileRole(name string, policyRules []v1.PolicyRule // if the Rules differ, update the Role if !reflect.DeepEqual(existingRole.Rules, role.Rules) { existingRole.Rules = role.Rules + argoutil.LogResourceUpdate(log, &existingRole, "updating policy rules") if err := r.Client.Update(context.TODO(), &existingRole); err != nil { return nil, err } @@ -247,7 +268,7 @@ func (r *ReconcileArgoCD) reconcileRoleForApplicationSourceNamespaces(name strin return fmt.Errorf("failed to reconcile the role for the service account associated with %s : %s", name, err) } - log.Info(fmt.Sprintf("creating role %s for Argo CD instance %s in namespace %s", role.Name, cr.Name, namespace)) + argoutil.LogResourceCreation(log, role) if err := r.Client.Create(context.TODO(), role); err != nil { return err } @@ -263,6 +284,7 @@ func (r *ReconcileArgoCD) reconcileRoleForApplicationSourceNamespaces(name strin namespace.Labels = make(map[string]string) } namespace.Labels[common.ArgoCDManagedByClusterArgoCDLabel] = cr.Namespace + argoutil.LogResourceUpdate(log, namespace, fmt.Sprintf("adding label '%s=%s'", common.ArgoCDManagedByClusterArgoCDLabel, cr.Namespace)) if err := r.Client.Update(context.TODO(), namespace); err != nil { log.Error(err, fmt.Sprintf("failed to add label from namespace [%s]", namespace.Name)) } @@ -270,6 +292,7 @@ func (r *ReconcileArgoCD) reconcileRoleForApplicationSourceNamespaces(name strin // if the Rules differ, update the Role if !created && !reflect.DeepEqual(existingRole.Rules, role.Rules) { existingRole.Rules = role.Rules + argoutil.LogResourceUpdate(log, &existingRole, "updating policy rules") if err := r.Client.Update(context.TODO(), &existingRole); err != nil { return err } @@ -320,6 +343,7 @@ func (r *ReconcileArgoCD) reconcileClusterRole(componentName string, policyRules // if current mode is default mode, but last one was aggregated mode, then delete ClusterRoles for View and Admin permissions if componentName == common.ArgoCDApplicationControllerComponentView || componentName == common.ArgoCDApplicationControllerComponentAdmin { if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: expectedClusterRole.Name}, expectedClusterRole); err == nil { + argoutil.LogResourceDeletion(log, expectedClusterRole, "aggregated cluster role mode is not enabled") if err := r.Client.Delete(context.TODO(), expectedClusterRole); err != nil { return nil, fmt.Errorf("failed to delete aggregated ClusterRoles: %s", expectedClusterRole.Name) } @@ -353,24 +377,28 @@ func (r *ReconcileArgoCD) reconcileClusterRole(componentName string, policyRules return nil, nil } + argoutil.LogResourceCreation(log, expectedClusterRole) return expectedClusterRole, r.Client.Create(context.TODO(), expectedClusterRole) } if !allowed { // delete existing ClusterRole as namespace can not host cluster-scoped Argo CD instance + argoutil.LogResourceDeletion(log, existingClusterRole, fmt.Sprintf("namespace '%s' cannot host cluster-scoped argocd instance", cr.Namespace)) return nil, r.Client.Delete(context.TODO(), existingClusterRole) } changed := false + var explanation string // if existing ClusterRole field values differ from expected values then update them if cr.Spec.AggregatedClusterRoles { - changed = matchAggregatedClusterRoleFields(expectedClusterRole, existingClusterRole, componentName) + changed, explanation = matchAggregatedClusterRoleFields(expectedClusterRole, existingClusterRole, componentName) } else { - changed = matchDefaultClusterRoleFields(expectedClusterRole, existingClusterRole, componentName) + changed, explanation = matchDefaultClusterRoleFields(expectedClusterRole, existingClusterRole, componentName) } if changed { + argoutil.LogResourceUpdate(log, existingClusterRole, "updating", explanation) if err := r.Client.Update(context.TODO(), existingClusterRole); err != nil { return nil, err } @@ -381,6 +409,7 @@ func (r *ReconcileArgoCD) reconcileClusterRole(componentName string, policyRules func deleteClusterRoles(c client.Client, clusterRoleList *v1.ClusterRoleList) error { for _, clusterRole := range clusterRoleList.Items { + argoutil.LogResourceDeletion(log, &clusterRole, "cleaning up cluster resources") if err := c.Delete(context.TODO(), &clusterRole); err != nil { return fmt.Errorf("failed to delete ClusterRole %q during cleanup: %w", clusterRole.Name, err) } @@ -397,6 +426,7 @@ func checkCustomClusterRoleMode(r *ReconcileArgoCD, cr *argoproj.ArgoCD, compone existingClusterRole := &v1.ClusterRole{} if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: GenerateUniqueResourceName(componentName, cr)}, existingClusterRole); err == nil { // default ClusterRole exists, now delete it + argoutil.LogResourceDeletion(log, existingClusterRole, "custom clusterrole mode is enabled, deleting default cluster role") if err := r.Client.Delete(context.TODO(), existingClusterRole); err != nil { return true, fmt.Errorf("failed to delete existing cluster role for the service account associated with %s : %s", componentName, err) } @@ -456,9 +486,10 @@ func configureAggregatedClusterRole(cr *argoproj.ArgoCD, clusterRole *v1.Cluster } // matchAggregatedClusterRoleFields compares field values of expected and existing ClusterRoles for aggregated ClusterRole -func matchAggregatedClusterRoleFields(expectedClusterRole *v1.ClusterRole, existingClusterRole *v1.ClusterRole, name string) bool { +func matchAggregatedClusterRoleFields(expectedClusterRole *v1.ClusterRole, existingClusterRole *v1.ClusterRole, name string) (bool, string) { changed := false aggregatedClusterRoleExists := true + var explanation string // if it is base ClusterRole then compare AggregationRule, Annotations and Rules if name == common.ArgoCDApplicationControllerComponent { @@ -466,11 +497,16 @@ func matchAggregatedClusterRoleFields(expectedClusterRole *v1.ClusterRole, exist if !reflect.DeepEqual(existingClusterRole.AggregationRule, expectedClusterRole.AggregationRule) { aggregatedClusterRoleExists = false existingClusterRole.AggregationRule = expectedClusterRole.AggregationRule + explanation = "aggregation rule" changed = true } if !reflect.DeepEqual(existingClusterRole.Annotations, expectedClusterRole.Annotations) { existingClusterRole.Annotations = expectedClusterRole.Annotations + if changed { + explanation += ", " + } + explanation += "annotations" changed = true } @@ -484,6 +520,10 @@ func matchAggregatedClusterRoleFields(expectedClusterRole *v1.ClusterRole, exist if name == common.ArgoCDApplicationControllerComponentView { if !reflect.DeepEqual(existingClusterRole.Labels, expectedClusterRole.Labels) { existingClusterRole.Labels = expectedClusterRole.Labels + if changed { + explanation += ", " + } + explanation += "labels" changed = true } } @@ -492,31 +532,45 @@ func matchAggregatedClusterRoleFields(expectedClusterRole *v1.ClusterRole, exist if name == common.ArgoCDApplicationControllerComponentAdmin { if !reflect.DeepEqual(existingClusterRole.AggregationRule, expectedClusterRole.AggregationRule) { existingClusterRole.AggregationRule = expectedClusterRole.AggregationRule + if changed { + explanation += ", " + } + explanation += "aggregation rule" changed = true } if !reflect.DeepEqual(existingClusterRole.Labels, expectedClusterRole.Labels) { existingClusterRole.Labels = expectedClusterRole.Labels + if changed { + explanation += ", " + } + explanation += "labels" changed = true } } - return changed + return changed, explanation } // matchDefaultClusterRoleFields compares field values of expected and existing ClusterRoles for default ClusterRole -func matchDefaultClusterRoleFields(expectedClusterRole *v1.ClusterRole, existingClusterRole *v1.ClusterRole, name string) bool { +func matchDefaultClusterRoleFields(expectedClusterRole *v1.ClusterRole, existingClusterRole *v1.ClusterRole, name string) (bool, string) { changed := false + var explanation string // if it is base ClusterRole then compare AggregationRule and Annotations if name == common.ArgoCDApplicationControllerComponent { if !reflect.DeepEqual(existingClusterRole.AggregationRule, expectedClusterRole.AggregationRule) { existingClusterRole.AggregationRule = expectedClusterRole.AggregationRule + explanation = "aggregation rule" changed = true } if !reflect.DeepEqual(existingClusterRole.Annotations, expectedClusterRole.Annotations) { existingClusterRole.Annotations = expectedClusterRole.Annotations + if changed { + explanation += ", " + } + explanation += "annotations" changed = true } } @@ -524,10 +578,14 @@ func matchDefaultClusterRoleFields(expectedClusterRole *v1.ClusterRole, existing // for all default ClusterRoles compare Rules if !reflect.DeepEqual(existingClusterRole.Rules, expectedClusterRole.Rules) { existingClusterRole.Rules = expectedClusterRole.Rules + if changed { + explanation += ", " + } + explanation += "policy rules" changed = true } - return changed + return changed, explanation } func verifyInstallationMode(cr *argoproj.ArgoCD, allowed bool) error { diff --git a/controllers/argocd/rolebinding.go b/controllers/argocd/rolebinding.go index a002e7957..e2f57e430 100644 --- a/controllers/argocd/rolebinding.go +++ b/controllers/argocd/rolebinding.go @@ -115,6 +115,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul if namespace.DeletionTimestamp != nil { if _, ok := namespace.Labels[common.ArgoCDManagedByLabel]; ok { delete(namespace.Labels, common.ArgoCDManagedByLabel) + argoutil.LogResourceUpdate(log, &namespace, "namespace is terminating, removing 'managed-by' label") _ = r.Client.Update(context.TODO(), &namespace) } continue @@ -180,7 +181,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul if roleBindingExists { if (name == common.ArgoCDDexServerComponent && !UseDex(cr)) || !UseApplicationController(name, cr) || !UseRedis(name, cr) || !UseServer(name, cr) { // Delete any existing RoleBinding created for Dex since dex uninstallation is requested - log.Info("deleting the existing Dex roleBinding because dex uninstallation is requested") + argoutil.LogResourceDeletion(log, existingRoleBinding, "dex is being uninstalled") if err = r.Client.Delete(context.TODO(), existingRoleBinding); err != nil { return err } @@ -189,6 +190,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul // if the RoleRef changes, delete the existing role binding and create a new one if !reflect.DeepEqual(roleBinding.RoleRef, existingRoleBinding.RoleRef) { + argoutil.LogResourceDeletion(log, existingRoleBinding, "role ref changed, deleting role binding in order to recreate it") if err = r.Client.Delete(context.TODO(), existingRoleBinding); err != nil { return err } @@ -196,6 +198,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul // if the Subjects differ, update the role bindings if !reflect.DeepEqual(roleBinding.Subjects, existingRoleBinding.Subjects) { existingRoleBinding.Subjects = roleBinding.Subjects + argoutil.LogResourceUpdate(log, existingRoleBinding, "updating subjects") if err = r.Client.Update(context.TODO(), existingRoleBinding); err != nil { return err } @@ -211,7 +214,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul } } - log.Info(fmt.Sprintf("creating rolebinding %s for Argo CD instance %s in namespace %s", roleBinding.Name, cr.Name, cr.Namespace)) + argoutil.LogResourceCreation(log, roleBinding) if err = r.Client.Create(context.TODO(), roleBinding); err != nil { return err } @@ -289,6 +292,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul } // if the RoleRef changes, delete the existing role binding and create a new one if !reflect.DeepEqual(roleBinding.RoleRef, existingRoleBinding.RoleRef) { + argoutil.LogResourceDeletion(log, existingRoleBinding, "role ref changed, deleting role binding in order to recreate it") if err = r.Client.Delete(context.TODO(), existingRoleBinding); err != nil { return err } @@ -296,6 +300,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul // if the Subjects differ, update the role bindings if !reflect.DeepEqual(roleBinding.Subjects, existingRoleBinding.Subjects) { existingRoleBinding.Subjects = roleBinding.Subjects + argoutil.LogResourceUpdate(log, existingRoleBinding, "updating subjects") if err = r.Client.Update(context.TODO(), existingRoleBinding); err != nil { return err } @@ -304,7 +309,7 @@ func (r *ReconcileArgoCD) reconcileRoleBinding(name string, rules []v1.PolicyRul } } - log.Info(fmt.Sprintf("creating rolebinding %s for Argo CD instance %s in namespace %s", roleBinding.Name, cr.Name, namespace)) + argoutil.LogResourceCreation(log, roleBinding) if err = r.Client.Create(context.TODO(), roleBinding); err != nil { return err } @@ -358,6 +363,7 @@ func (r *ReconcileArgoCD) reconcileClusterRoleBinding(name string, role *v1.Clus if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: GenerateUniqueResourceName(name, cr)}, existingClusterRoleBinding); err == nil { // Default ClusterRoleBinding exists, now delete it + argoutil.LogResourceDeletion(log, existingClusterRoleBinding, "default cluster-scoped role is disabled") if err := r.Client.Delete(context.TODO(), existingClusterRoleBinding); err != nil { return fmt.Errorf("failed to delete existing cluster role binding for the service account associated with %s : %s", name, err) } @@ -381,6 +387,7 @@ func (r *ReconcileArgoCD) reconcileClusterRoleBinding(name string, role *v1.Clus } if roleBindingExists && role == nil { + argoutil.LogResourceDeletion(log, roleBinding, "role binding has no corresponding role") return r.Client.Delete(context.TODO(), roleBinding) } @@ -409,13 +416,16 @@ func (r *ReconcileArgoCD) reconcileClusterRoleBinding(name string, role *v1.Clus } if roleBindingExists { + argoutil.LogResourceUpdate(log, roleBinding) return r.Client.Update(context.TODO(), roleBinding) } + argoutil.LogResourceCreation(log, roleBinding) return r.Client.Create(context.TODO(), roleBinding) } func deleteClusterRoleBindings(c client.Client, clusterBindingList *v1.ClusterRoleBindingList) error { for _, clusterBinding := range clusterBindingList.Items { + argoutil.LogResourceDeletion(log, &clusterBinding, "cleaning up cluster resources") if err := c.Delete(context.TODO(), &clusterBinding); err != nil { return fmt.Errorf("failed to delete ClusterRoleBinding %q during cleanup: %w", clusterBinding.Name, err) } diff --git a/controllers/argocd/route.go b/controllers/argocd/route.go index 14a3ef5f2..5b2c7246e 100644 --- a/controllers/argocd/route.go +++ b/controllers/argocd/route.go @@ -109,6 +109,7 @@ func (r *ReconcileArgoCD) reconcileGrafanaRoute(cr *argoproj.ArgoCD) error { //nolint:staticcheck if !cr.Spec.Grafana.Enabled || !cr.Spec.Grafana.Route.Enabled { // Route exists but enabled flag has been set to false, delete the Route + argoutil.LogResourceDeletion(log, route, "grafana or grafana route is disabled") return r.Client.Delete(context.TODO(), route) } log.Info(grafanaDeprecatedWarning) @@ -131,6 +132,13 @@ func (r *ReconcileArgoCD) reconcilePrometheusRoute(cr *argoproj.ArgoCD) error { if argoutil.IsObjectFound(r.Client, cr.Namespace, route.Name, route) { if !cr.Spec.Prometheus.Enabled || !cr.Spec.Prometheus.Route.Enabled { // Route exists but enabled flag has been set to false, delete the Route + var explanation string + if !cr.Spec.Prometheus.Enabled { + explanation = "prometheus is disabled" + } else { + explanation = "prometheus route is disabled" + } + argoutil.LogResourceDeletion(log, route, explanation) return r.Client.Delete(context.TODO(), route) } return nil // Route found, do nothing @@ -182,6 +190,7 @@ func (r *ReconcileArgoCD) reconcilePrometheusRoute(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, route, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, route) return r.Client.Create(context.TODO(), route) } @@ -193,6 +202,7 @@ func (r *ReconcileArgoCD) reconcileServerRoute(cr *argoproj.ArgoCD) error { if found { if !cr.Spec.Server.Route.Enabled { // Route exists but enabled flag has been set to false, delete the Route + argoutil.LogResourceDeletion(log, route, "server route is disabled") return r.Client.Delete(context.TODO(), route) } } @@ -282,8 +292,10 @@ func (r *ReconcileArgoCD) reconcileServerRoute(cr *argoproj.ArgoCD) error { return err } if !found { + argoutil.LogResourceCreation(log, route) return r.Client.Create(context.TODO(), route) } + argoutil.LogResourceUpdate(log, route) return r.Client.Update(context.TODO(), route) } @@ -319,6 +331,13 @@ func (r *ReconcileArgoCD) reconcileApplicationSetControllerWebhookRoute(cr *argo if found { if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Route.Enabled { // Route exists but enabled flag has been set to false, delete the Route + var explanation string + if cr.Spec.ApplicationSet == nil { + explanation = "applicationset is disabled" + } else { + explanation = "applicationset webhook route is disabled" + } + argoutil.LogResourceDeletion(log, route, explanation) return r.Client.Delete(context.TODO(), route) } } @@ -414,8 +433,10 @@ func (r *ReconcileArgoCD) reconcileApplicationSetControllerWebhookRoute(cr *argo return err } if !found { + argoutil.LogResourceCreation(log, route) return r.Client.Create(context.TODO(), route) } + argoutil.LogResourceUpdate(log, route) return r.Client.Update(context.TODO(), route) } diff --git a/controllers/argocd/secret.go b/controllers/argocd/secret.go index b1f58a73e..06d7cfa3d 100644 --- a/controllers/argocd/secret.go +++ b/controllers/argocd/secret.go @@ -196,6 +196,7 @@ func (r *ReconcileArgoCD) reconcileArgoSecret(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, secret) return r.Client.Create(context.TODO(), secret) } @@ -218,6 +219,7 @@ func (r *ReconcileArgoCD) reconcileClusterMainSecret(cr *argoproj.ArgoCD) error if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, secret) return r.Client.Create(context.TODO(), secret) } @@ -253,6 +255,7 @@ func (r *ReconcileArgoCD) reconcileClusterTLSSecret(cr *argoproj.ArgoCD) error { return err } + argoutil.LogResourceCreation(log, secret) return r.Client.Create(context.TODO(), secret) } @@ -271,6 +274,7 @@ func (r *ReconcileArgoCD) reconcileClusterCASecret(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, secret) return r.Client.Create(context.TODO(), secret) } @@ -306,6 +310,7 @@ func (r *ReconcileArgoCD) reconcileClusterSecrets(cr *argoproj.ArgoCD) error { // reconcileExistingArgoSecret will ensure that the Argo CD Secret is up to date. func (r *ReconcileArgoCD) reconcileExistingArgoSecret(cr *argoproj.ArgoCD, secret *corev1.Secret, clusterSecret *corev1.Secret, tlsSecret *corev1.Secret) error { changed := false + explanation := "" if secret.Data == nil { secret.Data = make(map[string][]byte) @@ -330,6 +335,7 @@ func (r *ReconcileArgoCD) reconcileExistingArgoSecret(cr *argoproj.ArgoCD, secre secret.Data[common.ArgoCDKeyAdminPassword] = []byte(hashedPassword) secret.Data[common.ArgoCDKeyAdminPasswordMTime] = nowBytes() + explanation = "argo admin password" changed = true } } @@ -337,6 +343,10 @@ func (r *ReconcileArgoCD) reconcileExistingArgoSecret(cr *argoproj.ArgoCD, secre if hasArgoTLSChanged(secret, tlsSecret) { secret.Data[common.ArgoCDKeyTLSCert] = tlsSecret.Data[common.ArgoCDKeyTLSCert] secret.Data[common.ArgoCDKeyTLSPrivateKey] = tlsSecret.Data[common.ArgoCDKeyTLSPrivateKey] + if changed { + explanation += ", " + } + explanation += "argo tls secret" changed = true } @@ -350,13 +360,17 @@ func (r *ReconcileArgoCD) reconcileExistingArgoSecret(cr *argoproj.ArgoCD, secre expected := *dexOIDCClientSecret if actual != expected { secret.Data[common.ArgoCDDexSecretKey] = []byte(*dexOIDCClientSecret) + if changed { + explanation += ", " + } + explanation += "argo dex secret" changed = true } } } if changed { - log.Info("updating argo secret") + argoutil.LogResourceUpdate(log, secret, "updating", explanation) if err := r.Client.Update(context.TODO(), secret); err != nil { return err } @@ -428,8 +442,10 @@ func (r *ReconcileArgoCD) reconcileClusterPermissionsSecret(cr *argoproj.ArgoCD) // if the cluster belongs to cluster config namespace, // remove all namespaces from cluster secret, // else update the list of namespaces if value differs. + var explanation string if clusterConfigInstance { delete(s.Data, "namespaces") + explanation = "removing namespaces from cluster secret" } else { ns := strings.Split(string(s.Data["namespaces"]), ",") for _, n := range namespaces { @@ -439,7 +455,9 @@ func (r *ReconcileArgoCD) reconcileClusterPermissionsSecret(cr *argoproj.ArgoCD) } sort.Strings(ns) s.Data["namespaces"] = []byte(strings.Join(ns, ",")) + explanation = "updating namespaces in cluster secret" } + argoutil.LogResourceUpdate(log, &s, explanation) return r.Client.Update(context.TODO(), &s) } } @@ -452,6 +470,7 @@ func (r *ReconcileArgoCD) reconcileClusterPermissionsSecret(cr *argoproj.ArgoCD) if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, secret) return r.Client.Create(context.TODO(), secret) } @@ -587,6 +606,7 @@ func (r *ReconcileArgoCD) reconcileRedisTLSSecret(cr *argoproj.ArgoCD, useTLSFor // So instead we delete the stateful set, which will delete all the pods. redisSts := newStatefulSetWithSuffix("redis-ha-server", "redis", cr) if argoutil.IsObjectFound(r.Client, redisSts.Namespace, redisSts.Name, redisSts) { + argoutil.LogResourceDeletion(log, redisSts, "to trigger pods to restart") err = r.Client.Delete(context.TODO(), redisSts) if err != nil { return err @@ -675,5 +695,6 @@ func (r *ReconcileArgoCD) reconcileRedisInitialPasswordSecret(cr *argoproj.ArgoC if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, secret) return r.Client.Create(context.TODO(), secret) } diff --git a/controllers/argocd/service.go b/controllers/argocd/service.go index 9556bc9a2..c5f76fd9d 100644 --- a/controllers/argocd/service.go +++ b/controllers/argocd/service.go @@ -74,6 +74,7 @@ func (r *ReconcileArgoCD) reconcileGrafanaService(cr *argoproj.ArgoCD) error { //nolint:staticcheck if !cr.Spec.Grafana.Enabled { // Service exists but enabled flag has been set to false, delete the Service + argoutil.LogResourceDeletion(log, svc, "grafana is disabled") return r.Client.Delete(context.TODO(), svc) } log.Info(grafanaDeprecatedWarning) @@ -113,6 +114,7 @@ func (r *ReconcileArgoCD) reconcileMetricsService(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -122,6 +124,13 @@ func (r *ReconcileArgoCD) reconcileRedisHAAnnounceServices(cr *argoproj.ArgoCD) svc := newServiceWithSuffix(fmt.Sprintf("redis-ha-announce-%d", i), "redis", cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, svc) { if !cr.Spec.HA.Enabled || !cr.Spec.Redis.IsEnabled() { + var explanation string + if !cr.Spec.HA.Enabled { + explanation = "ha is disabled" + } else { + explanation = "redis is disabled" + } + argoutil.LogResourceDeletion(log, svc, explanation) return r.Client.Delete(context.TODO(), svc) } return nil // Service found, do nothing @@ -160,6 +169,7 @@ func (r *ReconcileArgoCD) reconcileRedisHAAnnounceServices(cr *argoproj.ArgoCD) return err } + argoutil.LogResourceCreation(log, svc) if err := r.Client.Create(context.TODO(), svc); err != nil { return err } @@ -172,6 +182,13 @@ func (r *ReconcileArgoCD) reconcileRedisHAMasterService(cr *argoproj.ArgoCD) err svc := newServiceWithSuffix("redis-ha", "redis", cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, svc) { if !cr.Spec.HA.Enabled || !cr.Spec.Redis.IsEnabled() { + var explanation string + if !cr.Spec.HA.Enabled { + explanation = "ha is disabled" + } else { + explanation = "redis is disabled" + } + argoutil.LogResourceDeletion(log, svc, explanation) return r.Client.Delete(context.TODO(), svc) } return nil // Service found, do nothing @@ -202,6 +219,7 @@ func (r *ReconcileArgoCD) reconcileRedisHAMasterService(cr *argoproj.ArgoCD) err if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -211,10 +229,18 @@ func (r *ReconcileArgoCD) reconcileRedisHAProxyService(cr *argoproj.ArgoCD) erro if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, svc) { if !cr.Spec.HA.Enabled || !cr.Spec.Redis.IsEnabled() { + var explanation string + if !cr.Spec.HA.Enabled { + explanation = "ha is disabled" + } else { + explanation = "redis is disabled" + } + argoutil.LogResourceDeletion(log, svc, explanation) return r.Client.Delete(context.TODO(), svc) } if ensureAutoTLSAnnotation(r.Client, svc, common.ArgoCDRedisServerTLSSecretName, cr.Spec.Redis.WantsAutoTLS()) { + argoutil.LogResourceUpdate(log, svc, "updating auto tls annotation") return r.Client.Update(context.TODO(), svc) } return nil // Service found, do nothing @@ -242,6 +268,7 @@ func (r *ReconcileArgoCD) reconcileRedisHAProxyService(cr *argoproj.ArgoCD) erro if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -268,15 +295,19 @@ func (r *ReconcileArgoCD) reconcileRedisService(cr *argoproj.ArgoCD) error { if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, svc) { if !cr.Spec.Redis.IsEnabled() { + argoutil.LogResourceDeletion(log, svc, "redis is disabled") return r.Client.Delete(context.TODO(), svc) } if ensureAutoTLSAnnotation(r.Client, svc, common.ArgoCDRedisServerTLSSecretName, cr.Spec.Redis.WantsAutoTLS()) { + argoutil.LogResourceUpdate(log, svc, "updating auto tls annotation") return r.Client.Update(context.TODO(), svc) } if cr.Spec.HA.Enabled { + argoutil.LogResourceDeletion(log, svc, "ha is disabled") return r.Client.Delete(context.TODO(), svc) } if cr.Spec.Redis.IsRemote() { + argoutil.LogResourceDeletion(log, svc, "remote redis is configured") return r.Client.Delete(context.TODO(), svc) } return nil // Service found, do nothing @@ -309,6 +340,7 @@ func (r *ReconcileArgoCD) reconcileRedisService(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -364,13 +396,15 @@ func (r *ReconcileArgoCD) reconcileRepoService(cr *argoproj.ArgoCD) error { if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, svc) { if !cr.Spec.Repo.IsEnabled() { + argoutil.LogResourceDeletion(log, svc, "repo server is disabled") return r.Client.Delete(context.TODO(), svc) } if ensureAutoTLSAnnotation(r.Client, svc, common.ArgoCDRepoServerTLSSecretName, cr.Spec.Repo.WantsAutoTLS()) { + argoutil.LogResourceUpdate(log, svc, "updating auto tls annotation") return r.Client.Update(context.TODO(), svc) } if cr.Spec.Repo.IsRemote() { - log.Info("skip creating repo server service, repo remote is enabled") + argoutil.LogResourceDeletion(log, svc, "remote repo server is configured") return r.Client.Delete(context.TODO(), svc) } return nil // Service found, do nothing @@ -408,6 +442,7 @@ func (r *ReconcileArgoCD) reconcileRepoService(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -434,6 +469,7 @@ func (r *ReconcileArgoCD) reconcileServerMetricsService(cr *argoproj.ArgoCD) err if err := controllerutil.SetControllerReference(cr, svc, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } @@ -469,17 +505,25 @@ func (r *ReconcileArgoCD) reconcileServerService(cr *argoproj.ArgoCD) error { existingSVC := &corev1.Service{} if argoutil.IsObjectFound(r.Client, cr.Namespace, svc.Name, existingSVC) { changed := false + explanation := "" if !cr.Spec.Server.IsEnabled() { + argoutil.LogResourceDeletion(log, svc, "argocd server is disabled") return r.Client.Delete(context.TODO(), svc) } if ensureAutoTLSAnnotation(r.Client, existingSVC, common.ArgoCDServerTLSSecretName, cr.Spec.Server.WantsAutoTLS()) { + explanation = "auto tls annotation" changed = true } if !reflect.DeepEqual(svc.Spec.Type, existingSVC.Spec.Type) { existingSVC.Spec.Type = svc.Spec.Type + if changed { + explanation += ", " + } + explanation += "service type" changed = true } if changed { + argoutil.LogResourceUpdate(log, existingSVC, "updating", explanation) return r.Client.Update(context.TODO(), existingSVC) } return nil @@ -488,6 +532,7 @@ func (r *ReconcileArgoCD) reconcileServerService(cr *argoproj.ArgoCD) error { if !cr.Spec.Server.IsEnabled() { return nil } + argoutil.LogResourceCreation(log, svc) return r.Client.Create(context.TODO(), svc) } diff --git a/controllers/argocd/service_account.go b/controllers/argocd/service_account.go index e2ff200d9..59b58d6c3 100644 --- a/controllers/argocd/service_account.go +++ b/controllers/argocd/service_account.go @@ -120,7 +120,7 @@ func (r *ReconcileArgoCD) reconcileServiceAccount(name string, cr *argoproj.Argo if exists { if name == common.ArgoCDDexServerComponent && !UseDex(cr) { // Delete any existing Service Account created for Dex since dex is disabled - log.Info("deleting the existing Dex service account because dex uninstallation requested") + argoutil.LogResourceDeletion(log, sa, "dex is being uninstalled") return sa, r.Client.Delete(context.TODO(), sa) } return sa, nil @@ -130,8 +130,7 @@ func (r *ReconcileArgoCD) reconcileServiceAccount(name string, cr *argoproj.Argo return nil, err } - log.Info(fmt.Sprintf("creating serviceaccount %s for Argo CD instance %s in namespace %s", sa.Name, cr.Name, cr.Namespace)) - + argoutil.LogResourceCreation(log, sa) err := r.Client.Create(context.TODO(), sa) if err != nil { return nil, err diff --git a/controllers/argocd/statefulset.go b/controllers/argocd/statefulset.go index 80c9400e5..38cddf8ac 100644 --- a/controllers/argocd/statefulset.go +++ b/controllers/argocd/statefulset.go @@ -428,41 +428,70 @@ func (r *ReconcileArgoCD) reconcileRedisStatefulSet(cr *argoproj.ArgoCD) error { if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { if !(cr.Spec.HA.Enabled && cr.Spec.Redis.IsEnabled()) { // StatefulSet exists but either HA or component enabled flag has been set to false, delete the StatefulSet + var explanation string + if !cr.Spec.HA.Enabled { + explanation = "ha is disabled" + } else { + explanation = "redis is disabled" + } + argoutil.LogResourceDeletion(log, existing, explanation) return r.Client.Delete(context.TODO(), existing) } desiredImage := getRedisHAContainerImage(cr) changed := false - updateNodePlacementStateful(existing, ss, &changed) + explanation := "" + updateNodePlacementStateful(existing, ss, &changed, &explanation) for i, container := range existing.Spec.Template.Spec.Containers { if container.Image != desiredImage { existing.Spec.Template.Spec.Containers[i].Image = getRedisHAContainerImage(cr) existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + if changed { + explanation += ", " + } + explanation += fmt.Sprintf("container '%s' image", container.Name) changed = true } if !reflect.DeepEqual(ss.Spec.Template.Spec.Containers[i].Resources, existing.Spec.Template.Spec.Containers[i].Resources) { existing.Spec.Template.Spec.Containers[i].Resources = ss.Spec.Template.Spec.Containers[i].Resources + if changed { + explanation += ", " + } + explanation += fmt.Sprintf("container '%s' resources", container.Name) changed = true } if !reflect.DeepEqual(ss.Spec.Template.Spec.Containers[i].SecurityContext, existing.Spec.Template.Spec.Containers[i].SecurityContext) { existing.Spec.Template.Spec.Containers[i].SecurityContext = ss.Spec.Template.Spec.Containers[i].SecurityContext + if changed { + explanation += ", " + } + explanation += fmt.Sprintf("container '%s' security context", container.Name) changed = true } } if !reflect.DeepEqual(ss.Spec.Template.Spec.InitContainers[0].Resources, existing.Spec.Template.Spec.InitContainers[0].Resources) { existing.Spec.Template.Spec.InitContainers[0].Resources = ss.Spec.Template.Spec.InitContainers[0].Resources + if changed { + explanation += ", " + } + explanation += fmt.Sprintf("init container '%s' resources", existing.Spec.Template.Spec.InitContainers[0].Name) changed = true } if !reflect.DeepEqual(ss.Spec.Template.Spec.InitContainers[0].SecurityContext, existing.Spec.Template.Spec.InitContainers[0].SecurityContext) { existing.Spec.Template.Spec.InitContainers[0].SecurityContext = ss.Spec.Template.Spec.InitContainers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += fmt.Sprintf("init container '%s' security context", existing.Spec.Template.Spec.InitContainers[0].Name) changed = true } if changed { + argoutil.LogResourceUpdate(log, existing, "updating", explanation) return r.Client.Update(context.TODO(), existing) } @@ -486,6 +515,7 @@ func (r *ReconcileArgoCD) reconcileRedisStatefulSet(cr *argoproj.ArgoCD) error { if err := controllerutil.SetControllerReference(cr, ss, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, ss) return r.Client.Create(context.TODO(), ss) } @@ -738,6 +768,7 @@ func (r *ReconcileArgoCD) reconcileApplicationControllerStatefulSet(cr *argoproj invalidImagePod := containsInvalidImage(cr, r) if invalidImagePod { + argoutil.LogResourceDeletion(log, ss, "one or more pods has an invalid image") if err := r.Client.Delete(context.TODO(), ss); err != nil { return err } @@ -758,55 +789,89 @@ func (r *ReconcileArgoCD) reconcileApplicationControllerStatefulSet(cr *argoproj existing := newStatefulSetWithSuffix("application-controller", "application-controller", cr) if argoutil.IsObjectFound(r.Client, cr.Namespace, existing.Name, existing) { if !cr.Spec.Controller.IsEnabled() { - log.Info("Existing application controller found but should be disabled. Deleting Application Controller") // Delete existing deployment for Application Controller, if any .. + argoutil.LogResourceDeletion(log, existing, "application controller is disabled") return r.Client.Delete(context.TODO(), existing) } actualImage := existing.Spec.Template.Spec.Containers[0].Image desiredImage := getArgoContainerImage(cr) changed := false + explanation := "" if actualImage != desiredImage { existing.Spec.Template.Spec.Containers[0].Image = desiredImage existing.Spec.Template.ObjectMeta.Labels["image.upgraded"] = time.Now().UTC().Format("01022006-150406-MST") + explanation = "container image" changed = true } desiredCommand := getArgoApplicationControllerCommand(cr, useTLSForRedis) if isRepoServerTLSVerificationRequested(cr) { desiredCommand = append(desiredCommand, "--repo-server-strict-tls") } - updateNodePlacementStateful(existing, ss, &changed) + updateNodePlacementStateful(existing, ss, &changed, &explanation) if !reflect.DeepEqual(desiredCommand, existing.Spec.Template.Spec.Containers[0].Command) { existing.Spec.Template.Spec.Containers[0].Command = desiredCommand + if changed { + explanation += ", " + } + explanation += "container command" changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.InitContainers, ss.Spec.Template.Spec.InitContainers) { existing.Spec.Template.Spec.InitContainers = ss.Spec.Template.Spec.InitContainers + if changed { + explanation += ", " + } + explanation += "init containers" changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.Containers[0].Env, ss.Spec.Template.Spec.Containers[0].Env) { existing.Spec.Template.Spec.Containers[0].Env = ss.Spec.Template.Spec.Containers[0].Env + if changed { + explanation += ", " + } + explanation += "container env" changed = true } if !reflect.DeepEqual(ss.Spec.Template.Spec.Volumes, existing.Spec.Template.Spec.Volumes) { existing.Spec.Template.Spec.Volumes = ss.Spec.Template.Spec.Volumes + if changed { + explanation += ", " + } + explanation += "volumes" changed = true } if !reflect.DeepEqual(ss.Spec.Template.Spec.Containers[0].VolumeMounts, existing.Spec.Template.Spec.Containers[0].VolumeMounts) { existing.Spec.Template.Spec.Containers[0].VolumeMounts = ss.Spec.Template.Spec.Containers[0].VolumeMounts + if changed { + explanation += ", " + } + explanation += "container volume mounts" changed = true } if !reflect.DeepEqual(ss.Spec.Template.Spec.Containers[0].Resources, existing.Spec.Template.Spec.Containers[0].Resources) { existing.Spec.Template.Spec.Containers[0].Resources = ss.Spec.Template.Spec.Containers[0].Resources + if changed { + explanation += ", " + } + explanation += "container resources" changed = true } if !reflect.DeepEqual(ss.Spec.Template.Spec.Containers[0].SecurityContext, existing.Spec.Template.Spec.Containers[0].SecurityContext) { existing.Spec.Template.Spec.Containers[0].SecurityContext = ss.Spec.Template.Spec.Containers[0].SecurityContext + if changed { + explanation += ", " + } + explanation += "container security context" changed = true } if !reflect.DeepEqual(ss.Spec.Replicas, existing.Spec.Replicas) { existing.Spec.Replicas = ss.Spec.Replicas + if changed { + explanation += ", " + } + explanation += "replicas" changed = true } @@ -814,6 +879,10 @@ func (r *ReconcileArgoCD) reconcileApplicationControllerStatefulSet(cr *argoproj existing.Spec.Template.Spec.Containers[1:]) { existing.Spec.Template.Spec.Containers = append(existing.Spec.Template.Spec.Containers[0:1], ss.Spec.Template.Spec.Containers[1:]...) + if changed { + explanation += ", " + } + explanation += "additional containers" changed = true } @@ -823,14 +892,23 @@ func (r *ReconcileArgoCD) reconcileApplicationControllerStatefulSet(cr *argoproj if !reflect.DeepEqual(ss.Spec.Template.Annotations, existing.Spec.Template.Annotations) { 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 changed { + explanation += ", " + } + explanation += "labels" changed = true } if changed { + argoutil.LogResourceUpdate(log, existing, "updating", explanation) return r.Client.Update(context.TODO(), existing) } @@ -845,6 +923,7 @@ func (r *ReconcileArgoCD) reconcileApplicationControllerStatefulSet(cr *argoproj // Delete existing deployment for Application Controller, if any .. deploy := newDeploymentWithSuffix("application-controller", "application-controller", cr) if argoutil.IsObjectFound(r.Client, deploy.Namespace, deploy.Name, deploy) { + argoutil.LogResourceDeletion(log, deploy, "application controller is configured using stateful set, not deployment") if err := r.Client.Delete(context.TODO(), deploy); err != nil { return err } @@ -853,6 +932,7 @@ func (r *ReconcileArgoCD) reconcileApplicationControllerStatefulSet(cr *argoproj if err := controllerutil.SetControllerReference(cr, ss, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, ss) return r.Client.Create(context.TODO(), ss) } @@ -875,17 +955,26 @@ func (r *ReconcileArgoCD) triggerStatefulSetRollout(sts *appsv1.StatefulSet, key } sts.Spec.Template.ObjectMeta.Labels[key] = nowNano() + argoutil.LogResourceUpdate(log, sts, "to trigger rollout") return r.Client.Update(context.TODO(), sts) } // to update nodeSelector and tolerations in reconciler -func updateNodePlacementStateful(existing *appsv1.StatefulSet, ss *appsv1.StatefulSet, changed *bool) { +func updateNodePlacementStateful(existing *appsv1.StatefulSet, ss *appsv1.StatefulSet, changed *bool, explanation *string) { if !reflect.DeepEqual(existing.Spec.Template.Spec.NodeSelector, ss.Spec.Template.Spec.NodeSelector) { existing.Spec.Template.Spec.NodeSelector = ss.Spec.Template.Spec.NodeSelector + if *changed { + *explanation += ", " + } + *explanation += "node selector" *changed = true } if !reflect.DeepEqual(existing.Spec.Template.Spec.Tolerations, ss.Spec.Template.Spec.Tolerations) { existing.Spec.Template.Spec.Tolerations = ss.Spec.Template.Spec.Tolerations + if *changed { + *explanation += ", " + } + *explanation += "tolerations" *changed = true } } diff --git a/controllers/argocd/statefulset_test.go b/controllers/argocd/statefulset_test.go index 89195d93a..58b2b4426 100644 --- a/controllers/argocd/statefulset_test.go +++ b/controllers/argocd/statefulset_test.go @@ -621,13 +621,20 @@ func Test_UpdateNodePlacementStateful(t *testing.T) { } expectedChange := false actualChange := false - updateNodePlacementStateful(ss, ss, &actualChange) + explanation := "" + updateNodePlacementStateful(ss, ss, &actualChange, &explanation) if actualChange != expectedChange { - t.Fatalf("updateNodePlacement failed, value of changed: %t", actualChange) + t.Fatalf("updateNodePlacementStateful failed, value of changed: %t", actualChange) } - updateNodePlacementStateful(ss, ss2, &actualChange) + if explanation != "" { + t.Fatalf("updateNodePlacementStateful returned unexpected explanation: '%s'", explanation) + } + updateNodePlacementStateful(ss, ss2, &actualChange, &explanation) if actualChange == expectedChange { - t.Fatalf("updateNodePlacement failed, value of changed: %t", actualChange) + t.Fatalf("updateNodePlacementStateful failed, value of changed: %t", actualChange) + } + if explanation != "node selector, tolerations" { + t.Fatalf("updateNodePlacementStateful returned unexpected explanation: '%s'", explanation) } } diff --git a/controllers/argocd/util.go b/controllers/argocd/util.go index a52eed32c..160b12c2d 100644 --- a/controllers/argocd/util.go +++ b/controllers/argocd/util.go @@ -920,6 +920,7 @@ func (r *ReconcileArgoCD) removeManagedByLabelFromNamespaces(namespace string) e continue } delete(ns.Labels, common.ArgoCDManagedByLabel) + argoutil.LogResourceUpdate(log, ns, "removing 'managed-by' label") if err := r.Client.Update(context.TODO(), ns); err != nil { log.Error(err, fmt.Sprintf("failed to remove label from namespace [%s]", ns.Name)) } @@ -942,6 +943,7 @@ func argocdInstanceSelector(name string) (labels.Selector, error) { func (r *ReconcileArgoCD) removeDeletionFinalizer(argocd *argoproj.ArgoCD) error { argocd.Finalizers = removeString(argocd.GetFinalizers(), common.ArgoCDDeletionFinalizer) + argoutil.LogResourceUpdate(log, argocd, "removing deletion finalizer") if err := r.Client.Update(context.TODO(), argocd); err != nil { return fmt.Errorf("failed to remove deletion finalizer from %s: %w", argocd.Name, err) } @@ -950,6 +952,7 @@ func (r *ReconcileArgoCD) removeDeletionFinalizer(argocd *argoproj.ArgoCD) error func (r *ReconcileArgoCD) addDeletionFinalizer(argocd *argoproj.ArgoCD) error { argocd.Finalizers = append(argocd.Finalizers, common.ArgoCDDeletionFinalizer) + argoutil.LogResourceUpdate(log, argocd, "adding deletion finalizer") if err := r.Client.Update(context.TODO(), argocd); err != nil { return fmt.Errorf("failed to add deletion finalizer for %s: %w", argocd.Name, err) } @@ -1302,6 +1305,7 @@ func deleteRBACsForNamespace(sourceNS string, k8sClient kubernetes.Interface) er // Delete all the retrieved roles for _, role := range roles.Items { + argoutil.LogResourceDeletion(log, &role) err = k8sClient.RbacV1().Roles(sourceNS).Delete(context.TODO(), role.Name, metav1.DeleteOptions{}) if err != nil { log.Error(err, fmt.Sprintf("failed to delete roles for namespace: %s", sourceNS)) @@ -1317,6 +1321,7 @@ func deleteRBACsForNamespace(sourceNS string, k8sClient kubernetes.Interface) er // Delete all the retrieved role bindings for _, roleBinding := range roleBindings.Items { + argoutil.LogResourceDeletion(log, &roleBinding) err = k8sClient.RbacV1().RoleBindings(sourceNS).Delete(context.TODO(), roleBinding.Name, metav1.DeleteOptions{}) if err != nil { log.Error(err, fmt.Sprintf("failed to delete role binding for namespace: %s", sourceNS)) @@ -1353,6 +1358,7 @@ func deleteManagedNamespaceFromClusterSecret(ownerNS, sourceNS string, k8sClient secret.Data["namespaces"] = []byte(strings.Join(result, ",")) } // Update the secret with the updated list of namespaces + argoutil.LogResourceUpdate(log, &secret, "removing managed namespace", sourceNS) if _, err = k8sClient.CoreV1().Secrets(ownerNS).Update(context.TODO(), &secret, metav1.UpdateOptions{}); err != nil { log.Error(err, fmt.Sprintf("failed to update cluster permission secret for namespace: %s", ownerNS)) return err @@ -1495,6 +1501,7 @@ func (r *ReconcileArgoCD) cleanupUnmanagedSourceNamespaceResources(cr *argoproj. } // Remove managed-by-cluster-argocd from the namespace delete(namespace.Labels, common.ArgoCDManagedByClusterArgoCDLabel) + argoutil.LogResourceUpdate(log, &namespace, "removing 'managed-by-cluster-argocd' label from umanaged source namespace") if err := r.Client.Update(context.TODO(), &namespace); err != nil { log.Error(err, fmt.Sprintf("failed to remove label from namespace [%s]", namespace.Name)) } @@ -1508,6 +1515,7 @@ func (r *ReconcileArgoCD) cleanupUnmanagedSourceNamespaceResources(cr *argoproj. } } if existingRole.Name != "" { + argoutil.LogResourceDeletion(log, &existingRole, "cleaning up unmanaged source namespace") if err := r.Client.Delete(context.TODO(), &existingRole); err != nil { return err } @@ -1521,6 +1529,7 @@ func (r *ReconcileArgoCD) cleanupUnmanagedSourceNamespaceResources(cr *argoproj. } } if existingRoleBinding.Name != "" { + argoutil.LogResourceDeletion(log, existingRoleBinding, "cleaning up unmanaged source namespace") if err := r.Client.Delete(context.TODO(), existingRoleBinding); err != nil { return err } diff --git a/controllers/argocdexport/export.go b/controllers/argocdexport/export.go index 7aad286cb..3340a2ec8 100644 --- a/controllers/argocdexport/export.go +++ b/controllers/argocdexport/export.go @@ -74,6 +74,7 @@ func (r *ReconcileArgoCDExport) reconcileExportSecret(cr *argoprojv1alpha1.ArgoC return err } secret.Data[common.ArgoCDKeyBackupKey] = backupKey + argoutil.LogResourceUpdate(log, secret, "updating the backup key") return r.Client.Update(context.TODO(), secret) } @@ -92,6 +93,7 @@ func (r *ReconcileArgoCDExport) reconcileExportSecret(cr *argoprojv1alpha1.ArgoC if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, secret) return r.Client.Create(context.TODO(), secret) } diff --git a/controllers/argocdexport/job.go b/controllers/argocdexport/job.go index d692d5a53..223e35e84 100644 --- a/controllers/argocdexport/job.go +++ b/controllers/argocdexport/job.go @@ -234,6 +234,7 @@ func (r *ReconcileArgoCDExport) reconcileCronJob(cr *argoproj.ArgoCDExport) erro if argoutil.IsObjectFound(r.Client, cr.Namespace, cj.Name, cj) { if *cr.Spec.Schedule != cj.Spec.Schedule { cj.Spec.Schedule = *cr.Spec.Schedule + argoutil.LogResourceUpdate(log, cj, "updating the schedule") return r.Client.Update(context.TODO(), cj) } return nil @@ -256,6 +257,7 @@ func (r *ReconcileArgoCDExport) reconcileCronJob(cr *argoproj.ArgoCDExport) erro if err := controllerutil.SetControllerReference(cr, cj, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, cj) return r.Client.Create(context.TODO(), cj) } @@ -287,6 +289,7 @@ func (r *ReconcileArgoCDExport) reconcileJob(cr *argoproj.ArgoCDExport) error { if err := controllerutil.SetControllerReference(cr, job, r.Scheme); err != nil { return err } + argoutil.LogResourceCreation(log, job) return r.Client.Create(context.TODO(), job) } diff --git a/controllers/argocdexport/local.go b/controllers/argocdexport/local.go index b3eaf22a8..6e00a1b32 100644 --- a/controllers/argocdexport/local.go +++ b/controllers/argocdexport/local.go @@ -16,7 +16,6 @@ package argocdexport import ( "context" - "fmt" "strings" corev1 "k8s.io/api/core/v1" @@ -64,12 +63,11 @@ func (r *ReconcileArgoCDExport) reconcilePVC(cr *argoproj.ArgoCDExport) error { } // Create PVC - log.Info(fmt.Sprintf("creating new pvc: %s", pvc.Name)) + argoutil.LogResourceCreation(log, pvc) if err := r.Client.Create(context.TODO(), pvc); err != nil { return err } // Create event - log.Info("creating new event") return argoutil.CreateEvent(r.Client, "Normal", "Exporting", "Created claim for export process.", "PersistentVolumeClaimCreated", cr.ObjectMeta, cr.TypeMeta) } diff --git a/controllers/argocdexport/storage.go b/controllers/argocdexport/storage.go index 169fb23dc..1d69419b1 100644 --- a/controllers/argocdexport/storage.go +++ b/controllers/argocdexport/storage.go @@ -19,6 +19,7 @@ import ( argoproj "github.com/argoproj-labs/argocd-operator/api/v1alpha1" "github.com/argoproj-labs/argocd-operator/common" + "github.com/argoproj-labs/argocd-operator/controllers/argoutil" ) // reconcileStorage will ensure that the storage options for the ArgoCDExport are present. @@ -27,6 +28,7 @@ func (r *ReconcileArgoCDExport) reconcileStorage(cr *argoproj.ArgoCDExport) erro cr.Spec.Storage = &argoproj.ArgoCDExportStorageSpec{ Backend: common.ArgoCDExportStorageBackendLocal, } + argoutil.LogResourceUpdate(log, cr, "updating the storage backend to", common.ArgoCDExportStorageBackendLocal) return r.Client.Update(context.TODO(), cr) } diff --git a/controllers/argoutil/resource.go b/controllers/argoutil/resource.go index b5adada0f..51749e2a1 100644 --- a/controllers/argoutil/resource.go +++ b/controllers/argoutil/resource.go @@ -17,6 +17,7 @@ package argoutil import ( "context" "fmt" + "reflect" "strings" corev1 "k8s.io/api/core/v1" @@ -25,6 +26,8 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/go-logr/logr" + argoprojv1alpha1 "github.com/argoproj-labs/argocd-operator/api/v1alpha1" argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" "github.com/argoproj-labs/argocd-operator/common" @@ -70,6 +73,9 @@ func CreateEvent(client client.Client, eventType, action, message, reason string event.CreationTimestamp = metav1.Now() event.FirstTimestamp = event.CreationTimestamp event.LastTimestamp = event.CreationTimestamp + + explanation := fmt.Sprintf("involved object: '%s %s/%s', action: '%s', reason: '%s'", typeMeta.Kind, objectMeta.Namespace, objectMeta.Name, action, reason) + LogResourceCreation(log, event, explanation) return client.Create(context.TODO(), event) } @@ -122,3 +128,49 @@ func AnnotationsForCluster(cr *argoproj.ArgoCD) map[string]string { } return annotations } + +func LogResourceCreation(log logr.Logger, object metav1.Object, explanations ...string) { + LogResourceAction(log, "Creating", object, explanations...) +} + +func LogResourceUpdate(log logr.Logger, object metav1.Object, explanations ...string) { + LogResourceAction(log, "Updating", object, explanations...) +} + +func LogResourceDeletion(log logr.Logger, object metav1.Object, explanations ...string) { + LogResourceAction(log, "Deleting", object, explanations...) +} + +func LogResourceAction(log logr.Logger, action string, object metav1.Object, explanations ...string) { + if object == nil { + log.Error(nil, "missing object in LogResourceAction") + return + } + + typeName := reflect.TypeOf(object).String() + pos := strings.LastIndex(typeName, ".") + if pos >= 0 { + typeName = typeName[pos+1:] + } + + objectName := object.GetName() + if len(objectName) == 0 { + objectName = object.GetGenerateName() + "" + } + + var msg string + if len(object.GetNamespace()) == 0 { + msg = fmt.Sprintf("%s %s '%s'", action, typeName, objectName) + } else { + msg = fmt.Sprintf("%s %s '%s/%s'", action, typeName, object.GetNamespace(), objectName) + } + + if len(explanations) > 0 { + msg += " -" + for s := range explanations { + msg += " " + explanations[s] + } + } + + log.Info(msg) +} diff --git a/controllers/argoutil/secret.go b/controllers/argoutil/secret.go index 83a014d1d..68fb9fe87 100644 --- a/controllers/argoutil/secret.go +++ b/controllers/argoutil/secret.go @@ -77,6 +77,7 @@ func CreateTLSSecret(client client.Client, name string, namespace string, data m Type: corev1.SecretTypeTLS, Data: data, } + LogResourceCreation(log, &secret) return client.Create(context.TODO(), &secret) } @@ -88,5 +89,6 @@ func CreateSecret(client client.Client, name string, namespace string, data map[ }, Data: data, } + LogResourceCreation(log, &secret) return client.Create(context.TODO(), &secret) } diff --git a/controllers/notificationsconfiguration/configmap.go b/controllers/notificationsconfiguration/configmap.go index fd81188e0..8ecf4adb7 100644 --- a/controllers/notificationsconfiguration/configmap.go +++ b/controllers/notificationsconfiguration/configmap.go @@ -36,6 +36,7 @@ func (r *NotificationsConfigurationReconciler) reconcileNotificationsConfigmap(c return err } + argoutil.LogResourceCreation(log, NotificationsConfigMap) err := r.Client.Create(context.TODO(), NotificationsConfigMap) if err != nil { return err @@ -67,6 +68,7 @@ func (r *NotificationsConfigurationReconciler) reconcileNotificationsConfigmap(c if !reflect.DeepEqual(expectedConfiguration, NotificationsConfigMap.Data) { NotificationsConfigMap.Data = expectedConfiguration + argoutil.LogResourceUpdate(log, NotificationsConfigMap, "updating config map data") err := r.Client.Update(context.TODO(), NotificationsConfigMap) if err != nil { return err diff --git a/controllers/notificationsconfiguration/notificationsconfiguration_controller.go b/controllers/notificationsconfiguration/notificationsconfiguration_controller.go index e9897a521..33cc54255 100644 --- a/controllers/notificationsconfiguration/notificationsconfiguration_controller.go +++ b/controllers/notificationsconfiguration/notificationsconfiguration_controller.go @@ -33,6 +33,8 @@ import ( // blank assignment to verify that ReconcileNotificationsConfiguration implements reconcile.Reconciler var _ reconcile.Reconciler = &NotificationsConfigurationReconciler{} +var log = logr.Log.WithName("controller_notificationsconfiguration") + // NotificationsConfigurationReconciler reconciles a NotificationsConfiguration object type NotificationsConfigurationReconciler struct { client.Client diff --git a/tests/k8s/1-001_validate_basic/02-ingress-available.yaml b/tests/k8s/1-001_validate_basic/02-ingress-available.yaml index c720340bd..475508916 100644 --- a/tests/k8s/1-001_validate_basic/02-ingress-available.yaml +++ b/tests/k8s/1-001_validate_basic/02-ingress-available.yaml @@ -7,7 +7,7 @@ delete: name: example-argocd commands: # Sleep to allow resources to be completely deleted - - command: sleep 30s + - command: sleep 30 --- apiVersion: argoproj.io/v1alpha1 kind: ArgoCD diff --git a/tests/k8s/1-001_validate_basic/03-disable-admin.yaml b/tests/k8s/1-001_validate_basic/03-disable-admin.yaml index fd15a4ffb..f0d922307 100644 --- a/tests/k8s/1-001_validate_basic/03-disable-admin.yaml +++ b/tests/k8s/1-001_validate_basic/03-disable-admin.yaml @@ -7,7 +7,7 @@ delete: name: example-argocd commands: # Sleep to allow resources to be completely deleted - - command: sleep 30s + - command: sleep 30 --- apiVersion: argoproj.io/v1alpha1 kind: ArgoCD diff --git a/tests/k8s/1-001_validate_basic/04-export.yaml b/tests/k8s/1-001_validate_basic/04-export.yaml index 942ef3061..8554d05f4 100644 --- a/tests/k8s/1-001_validate_basic/04-export.yaml +++ b/tests/k8s/1-001_validate_basic/04-export.yaml @@ -7,7 +7,7 @@ delete: name: example-argocd commands: # Sleep to allow resources to be completely deleted - - command: sleep 30s + - command: sleep 30 --- apiVersion: argoproj.io/v1alpha1 kind: ArgoCD diff --git a/tests/k8s/1-001_validate_basic/05-applicationset.yaml b/tests/k8s/1-001_validate_basic/05-applicationset.yaml index f6582332d..e185fc10e 100644 --- a/tests/k8s/1-001_validate_basic/05-applicationset.yaml +++ b/tests/k8s/1-001_validate_basic/05-applicationset.yaml @@ -7,7 +7,7 @@ delete: name: example-argocd commands: # Sleep to allow resources to be completely deleted - - command: sleep 30s + - command: sleep 30 --- apiVersion: argoproj.io/v1alpha1 kind: ArgoCD @@ -17,4 +17,4 @@ spec: applicationSet: webhookServer: ingress: - enabled: true \ No newline at end of file + enabled: true