Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: log k8s create/update/delete actions #1615

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 84 additions & 20 deletions controllers/argocd/applicationset.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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...
Expand All @@ -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{{
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
}
Expand Down Expand Up @@ -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))
}
Expand Down Expand Up @@ -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
Expand All @@ -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)
}

Expand All @@ -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
Expand All @@ -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)
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -1049,28 +1113,28 @@ 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
}
} else {
// 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))
}
}

Expand Down
Loading
Loading