snapshots #10

Merged
jandre merged 69 commits from snapshots into master 2023-04-24 06:49:52 +00:00
2 changed files with 166 additions and 75 deletions
Showing only changes of commit 121e8b11e7 - Show all commits

View File

@ -36,6 +36,9 @@ type BackupConfigurationReconciler struct {
Scheme *runtime.Scheme Scheme *runtime.Scheme
Log logr.Logger Log logr.Logger
context.Context context.Context
Name string
Namespace string
backupConf formolv1alpha1.BackupConfiguration
} }
//+kubebuilder:rbac:groups=formol.desmojim.fr,resources=*,verbs=* //+kubebuilder:rbac:groups=formol.desmojim.fr,resources=*,verbs=*
@ -63,6 +66,8 @@ type BackupConfigurationReconciler struct {
func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
r.Context = ctx r.Context = ctx
r.Log = log.FromContext(ctx) r.Log = log.FromContext(ctx)
r.Name = req.NamespacedName.Name
r.Namespace = req.NamespacedName.Namespace
r.Log.V(1).Info("Enter Reconcile with req", "req", req, "reconciler", r) r.Log.V(1).Info("Enter Reconcile with req", "req", req, "reconciler", r)
@ -74,6 +79,7 @@ func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.
} }
return ctrl.Result{}, err return ctrl.Result{}, err
} }
r.backupConf = backupConf
finalizerName := "finalizer.backupconfiguration.formol.desmojim.fr" finalizerName := "finalizer.backupconfiguration.formol.desmojim.fr"
@ -82,7 +88,7 @@ func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.
if controllerutil.ContainsFinalizer(&backupConf, finalizerName) { if controllerutil.ContainsFinalizer(&backupConf, finalizerName) {
_ = r.DeleteSidecar(backupConf) _ = r.DeleteSidecar(backupConf)
_ = r.DeleteCronJob(backupConf) _ = r.DeleteCronJob(backupConf)
_ = r.deleteRBACSidecar(backupConf.Namespace) _ = r.deleteRBAC()
controllerutil.RemoveFinalizer(&backupConf, finalizerName) controllerutil.RemoveFinalizer(&backupConf, finalizerName)
if err := r.Update(ctx, &backupConf); err != nil { if err := r.Update(ctx, &backupConf); err != nil {
r.Log.Error(err, "unable to remove finalizer") r.Log.Error(err, "unable to remove finalizer")
@ -111,6 +117,10 @@ func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.
} else { } else {
backupConf.Status.ActiveCronJob = true backupConf.Status.ActiveCronJob = true
} }
if err = r.createBSCreatorRBAC(); err != nil {
r.Log.Error(err, "unable to create RBAC for the sidecar container")
return ctrl.Result{}, err
}
for _, target := range backupConf.Spec.Targets { for _, target := range backupConf.Spec.Targets {
if err := r.addSidecar(backupConf, target); err != nil { if err := r.addSidecar(backupConf, target); err != nil {

View File

@ -31,9 +31,13 @@ import (
) )
const ( const (
FORMOL_SA = "formol-controller" FORMOL_BS_CREATOR_SA = "bs-creator"
FORMOL_SIDECAR_ROLE = "formol:sidecar-role" FORMOL_BS_CREATOR_ROLE = "formol:bs-creator-role"
FORMOL_SIDECAR_CLUSTERROLE = "formol:sidecar-clusterrole" FORMOL_BS_CREATOR_ROLEBINDING = "formol:bs-creator-rolebinding"
FORMOL_SIDECAR_ROLE = "formol:sidecar-role"
FORMOL_SIDECAR_ROLEBINDING = "formol:sidecar-rolebinding"
FORMOL_SIDECAR_CLUSTERROLE = "formol:sidecar-clusterrole"
FORMOL_SIDECAR_CLUSTERROLEBINDING = "formol:sidecar-clusterrolebinding"
) )
func (r *BackupConfigurationReconciler) DeleteCronJob(backupConf formolv1alpha1.BackupConfiguration) error { func (r *BackupConfigurationReconciler) DeleteCronJob(backupConf formolv1alpha1.BackupConfiguration) error {
@ -93,7 +97,7 @@ func (r *BackupConfigurationReconciler) AddCronJob(backupConf formolv1alpha1.Bac
Template: corev1.PodTemplateSpec{ Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{ Spec: corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyOnFailure, RestartPolicy: corev1.RestartPolicyOnFailure,
ServiceAccountName: "backupsession-creator", ServiceAccountName: FORMOL_BS_CREATOR_SA,
Containers: []corev1.Container{ Containers: []corev1.Container{
corev1.Container{ corev1.Container{
Name: "job-createbackupsession-" + backupConf.Name, Name: "job-createbackupsession-" + backupConf.Name,
@ -234,12 +238,7 @@ func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.Bac
return err return err
} }
if !hasSidecar(targetPodSpec) { if !hasSidecar(targetPodSpec) {
if err = r.createRBACSidecar(corev1.ServiceAccount{ if err = r.createSidecarRBAC(targetPodSpec); err != nil {
ObjectMeta: metav1.ObjectMeta{
Namespace: backupConf.Namespace,
Name: targetPodSpec.ServiceAccountName,
},
}); err != nil {
r.Log.Error(err, "unable to create RBAC for the sidecar container") r.Log.Error(err, "unable to create RBAC for the sidecar container")
return return
} }
@ -290,78 +289,146 @@ func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.Bac
} }
// Delete the sidecar role is there is no more sidecar container in the namespace // Delete the sidecar role is there is no more sidecar container in the namespace
func (r *BackupConfigurationReconciler) deleteRBACSidecar(namespace string) error { func (r *BackupConfigurationReconciler) deleteRBAC() error {
podList := corev1.PodList{} for _, roleBindingName := range []string{FORMOL_BS_CREATOR_ROLEBINDING, FORMOL_SIDECAR_CLUSTERROLEBINDING} {
if err := r.List(r.Context, &podList, &client.ListOptions{ roleBinding := rbacv1.RoleBinding{}
Namespace: namespace, if err := r.Get(r.Context, client.ObjectKey{
}); err != nil { Namespace: r.Namespace,
r.Log.Error(err, "unable to get the list of pods", "namespace", namespace) Name: roleBindingName,
return err }, &roleBinding); err == nil {
} if err = r.Delete(r.Context, &roleBinding); err != nil {
for _, pod := range podList.Items { r.Log.Error(err, "unable to delete role binding", "role binding", roleBindingName)
for _, container := range pod.Spec.Containers {
for _, env := range container.Env {
if env.Name == formolv1alpha1.SIDECARCONTAINER_NAME {
// There is still a sidecar in the namespace.
// cannot delete the sidecar role
return nil
}
} }
} }
} }
roleBinding := rbacv1.RoleBinding{ for _, roleName := range []string{FORMOL_BS_CREATOR_ROLE, FORMOL_SIDECAR_CLUSTERROLE} {
ObjectMeta: metav1.ObjectMeta{ role := rbacv1.Role{}
Namespace: namespace, if err := r.Get(r.Context, client.ObjectKey{
Name: FORMOL_SIDECAR_ROLE, Namespace: r.Namespace,
}, Name: roleName,
}, &role); err == nil {
if err = r.Delete(r.Context, &role); err != nil {
r.Log.Error(err, "unable to delete role", "role", roleName)
}
}
} }
if err := r.Delete(r.Context, &roleBinding); err != nil { sa := corev1.ServiceAccount{}
r.Log.Error(err, "unable to delete sidecar role binding") if err := r.Get(r.Context, client.ObjectKey{
Namespace: r.Namespace,
Name: FORMOL_BS_CREATOR_SA,
}, &sa); err == nil {
if err = r.Delete(r.Context, &sa); err != nil {
r.Log.Error(err, "unable to delete bs service account role")
}
} }
role := rbacv1.Role{ clusterRoleBinding := rbacv1.ClusterRoleBinding{}
ObjectMeta: metav1.ObjectMeta{ if err := r.Get(r.Context, client.ObjectKey{
Namespace: namespace, Namespace: r.Namespace,
Name: FORMOL_SIDECAR_ROLE, Name: FORMOL_SIDECAR_CLUSTERROLEBINDING,
}, }, &clusterRoleBinding); err == nil {
if err = r.Delete(r.Context, &clusterRoleBinding); err != nil {
r.Log.Error(err, "unable to delete sidecar cluster role binding")
}
} }
if err := r.Delete(r.Context, &role); err != nil { clusterRole := rbacv1.ClusterRole{}
r.Log.Error(err, "unable to delete sidecar role") if err := r.Get(r.Context, client.ObjectKey{
Namespace: r.Namespace,
Name: FORMOL_SIDECAR_CLUSTERROLE,
}, &clusterRole); err == nil {
if err = r.Delete(r.Context, &clusterRole); err != nil {
r.Log.Error(err, "unable to delete sidecar cluster role")
}
} }
clusterRoleBinding := rbacv1.ClusterRoleBinding{ return nil
ObjectMeta: metav1.ObjectMeta{ }
Namespace: namespace,
Name: FORMOL_SIDECAR_CLUSTERROLE, func (r *BackupConfigurationReconciler) createBSCreatorRBAC() error {
}, sa := corev1.ServiceAccount{}
if err := r.Get(r.Context, client.ObjectKey{
Namespace: r.Namespace,
Name: FORMOL_BS_CREATOR_SA,
}, &sa); errors.IsNotFound(err) {
sa = corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Namespace: r.Namespace,
Name: FORMOL_BS_CREATOR_SA,
},
}
if err = r.Create(r.Context, &sa); err != nil {
r.Log.Error(err, "unable to create BS creator SA")
return err
}
} }
if err := r.Delete(r.Context, &clusterRoleBinding); err != nil { role := rbacv1.Role{}
r.Log.Error(err, "unable to delete sidecar clusterRole binding") if err := r.Get(r.Context, client.ObjectKey{
Namespace: r.Namespace,
Name: FORMOL_BS_CREATOR_ROLE,
}, &role); errors.IsNotFound(err) {
role = rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Namespace: r.Namespace,
Name: FORMOL_BS_CREATOR_ROLE,
},
Rules: []rbacv1.PolicyRule{
rbacv1.PolicyRule{
Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"},
APIGroups: []string{"formol.desmojim.fr"},
Resources: []string{"backupsessions"},
},
},
}
r.Log.V(0).Info("Creating formol bs creator role", "role", role)
if err = r.Create(r.Context, &role); err != nil {
r.Log.Error(err, "unable to create bs creator role")
return err
}
} }
clusterRole := rbacv1.ClusterRole{ rolebinding := rbacv1.RoleBinding{}
ObjectMeta: metav1.ObjectMeta{ if err := r.Get(r.Context, client.ObjectKey{
Namespace: namespace, Namespace: r.Namespace,
Name: FORMOL_SIDECAR_CLUSTERROLE, Name: FORMOL_BS_CREATOR_ROLEBINDING,
}, }, &rolebinding); errors.IsNotFound(err) {
} rolebinding = rbacv1.RoleBinding{
if err := r.Delete(r.Context, &clusterRole); err != nil { ObjectMeta: metav1.ObjectMeta{
r.Log.Error(err, "unable to delete sidecar clusterRole") Namespace: r.Namespace,
Name: FORMOL_BS_CREATOR_ROLEBINDING,
},
Subjects: []rbacv1.Subject{
rbacv1.Subject{
Kind: "ServiceAccount",
Name: FORMOL_BS_CREATOR_SA,
},
},
RoleRef: rbacv1.RoleRef{
APIGroup: "rbac.authorization.k8s.io",
Kind: "Role",
Name: FORMOL_BS_CREATOR_ROLE,
},
}
r.Log.V(0).Info("Creating formol bs creator rolebinding", "rolebinding", rolebinding)
if err = r.Create(r.Context, &rolebinding); err != nil {
r.Log.Error(err, "unable to create bs creator rolebinding")
return err
}
} }
return nil return nil
} }
// Creates a role to allow the BackupSession controller in the sidecar to have access to resources // Creates a role to allow the BackupSession controller in the sidecar to have access to resources
// like Repo, Functions, ... // like Repo, Functions, ...
func (r *BackupConfigurationReconciler) createRBACSidecar(sa corev1.ServiceAccount) error { func (r *BackupConfigurationReconciler) createSidecarRBAC(podSpec *corev1.PodSpec) error {
if sa.Name == "" { sa := podSpec.ServiceAccountName
sa.Name = "default" if sa == "" {
sa = "default"
} }
role := rbacv1.Role{} role := rbacv1.Role{}
if err := r.Get(r.Context, client.ObjectKey{ if err := r.Get(r.Context, client.ObjectKey{
Namespace: sa.Namespace, Namespace: r.Namespace,
Name: FORMOL_SIDECAR_ROLE, Name: FORMOL_SIDECAR_ROLE,
}, &role); err != nil && errors.IsNotFound(err) { }, &role); errors.IsNotFound(err) {
role = rbacv1.Role{ role = rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: sa.Namespace, Namespace: r.Namespace,
Name: FORMOL_SIDECAR_ROLE, Name: FORMOL_SIDECAR_ROLE,
}, },
Rules: []rbacv1.PolicyRule{ Rules: []rbacv1.PolicyRule{
@ -405,18 +472,18 @@ func (r *BackupConfigurationReconciler) createRBACSidecar(sa corev1.ServiceAccou
} }
rolebinding := rbacv1.RoleBinding{} rolebinding := rbacv1.RoleBinding{}
if err := r.Get(r.Context, client.ObjectKey{ if err := r.Get(r.Context, client.ObjectKey{
Namespace: sa.Namespace, Namespace: r.Namespace,
Name: FORMOL_SIDECAR_ROLE, Name: FORMOL_SIDECAR_ROLEBINDING,
}, &rolebinding); err != nil && errors.IsNotFound(err) { }, &rolebinding); errors.IsNotFound(err) {
rolebinding = rbacv1.RoleBinding{ rolebinding = rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Namespace: sa.Namespace, Namespace: r.Namespace,
Name: FORMOL_SIDECAR_ROLE, Name: FORMOL_SIDECAR_ROLEBINDING,
}, },
Subjects: []rbacv1.Subject{ Subjects: []rbacv1.Subject{
rbacv1.Subject{ rbacv1.Subject{
Kind: "ServiceAccount", Kind: "ServiceAccount",
Name: sa.Name, Name: sa,
}, },
}, },
RoleRef: rbacv1.RoleRef{ RoleRef: rbacv1.RoleRef{
@ -430,11 +497,25 @@ func (r *BackupConfigurationReconciler) createRBACSidecar(sa corev1.ServiceAccou
r.Log.Error(err, "unable to create sidecar rolebinding") r.Log.Error(err, "unable to create sidecar rolebinding")
return err return err
} }
} else {
if err != nil {
r.Log.Error(err, "something went very wrong here")
return err
}
rolebinding.Subjects = append(rolebinding.Subjects, rbacv1.Subject{
Kind: "ServiceAccount",
Name: sa,
})
r.Log.V(0).Info("Updating formol sidecar rolebinding with the new SA", "rolebinding", rolebinding)
if err = r.Update(r.Context, &rolebinding); err != nil {
r.Log.Error(err, "unable to update sidecar rolebinding")
return err
}
} }
clusterRole := rbacv1.ClusterRole{} clusterRole := rbacv1.ClusterRole{}
if err := r.Get(r.Context, client.ObjectKey{ if err := r.Get(r.Context, client.ObjectKey{
Name: FORMOL_SIDECAR_CLUSTERROLE, Name: FORMOL_SIDECAR_CLUSTERROLE,
}, &clusterRole); err != nil && errors.IsNotFound(err) { }, &clusterRole); errors.IsNotFound(err) {
clusterRole = rbacv1.ClusterRole{ clusterRole = rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: FORMOL_SIDECAR_CLUSTERROLE, Name: FORMOL_SIDECAR_CLUSTERROLE,
@ -460,18 +541,18 @@ func (r *BackupConfigurationReconciler) createRBACSidecar(sa corev1.ServiceAccou
} }
clusterRolebinding := rbacv1.ClusterRoleBinding{} clusterRolebinding := rbacv1.ClusterRoleBinding{}
if err := r.Get(r.Context, client.ObjectKey{ if err := r.Get(r.Context, client.ObjectKey{
Namespace: sa.Namespace, Namespace: r.Namespace,
Name: FORMOL_SIDECAR_CLUSTERROLE, Name: FORMOL_SIDECAR_CLUSTERROLEBINDING,
}, &clusterRolebinding); err != nil && errors.IsNotFound(err) { }, &clusterRolebinding); errors.IsNotFound(err) {
clusterRolebinding = rbacv1.ClusterRoleBinding{ clusterRolebinding = rbacv1.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: FORMOL_SIDECAR_CLUSTERROLE, Name: FORMOL_SIDECAR_CLUSTERROLEBINDING,
}, },
Subjects: []rbacv1.Subject{ Subjects: []rbacv1.Subject{
rbacv1.Subject{ rbacv1.Subject{
Kind: "ServiceAccount", Kind: "ServiceAccount",
Name: sa.Name, Name: sa,
Namespace: sa.Namespace, Namespace: r.Namespace,
}, },
}, },
RoleRef: rbacv1.RoleRef{ RoleRef: rbacv1.RoleRef{