added BackupConfiguration.Status.Targets struct to hold the paths to be backed up in the sidecar container

This commit is contained in:
Jean-Marc ANDRE 2023-02-16 21:40:22 +01:00
parent 55f3dc8dff
commit c89a522262
4 changed files with 67 additions and 19 deletions

View File

@ -38,6 +38,8 @@ const (
JobKind BackupType = "Job"
)
const BACKUP_PREFIX_PATH = `backup`
type Step struct {
Name string `json:"name"`
// +optional
@ -59,6 +61,11 @@ type Target struct {
Retry int `json:"retry"`
}
type TargetSidecarPath struct {
TargetName string `json:"targetName"`
SidecarPaths []string `json:"sidecarPaths"`
}
type Keep struct {
Last int32 `json:"last"`
Daily int32 `json:"daily"`
@ -84,6 +91,8 @@ type BackupConfigurationStatus struct {
Suspended bool `json:"suspended"`
ActiveCronJob bool `json:"activeCronJob"`
ActiveSidecar bool `json:"activeSidecar"`
// +optional
Targets []TargetSidecarPath `json:"targets,omitempty"`
}
//+kubebuilder:object:root=true

View File

@ -145,6 +145,13 @@ func (in *BackupConfigurationStatus) DeepCopyInto(out *BackupConfigurationStatus
in, out := &in.LastBackupTime, &out.LastBackupTime
*out = (*in).DeepCopy()
}
if in.Targets != nil {
in, out := &in.Targets, &out.Targets
*out = make([]TargetSidecarPath, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupConfigurationStatus.
@ -610,6 +617,26 @@ func (in *TargetContainer) DeepCopy() *TargetContainer {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TargetSidecarPath) DeepCopyInto(out *TargetSidecarPath) {
*out = *in
if in.SidecarPaths != nil {
in, out := &in.SidecarPaths, &out.SidecarPaths
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetSidecarPath.
func (in *TargetSidecarPath) DeepCopy() *TargetSidecarPath {
if in == nil {
return nil
}
out := new(TargetSidecarPath)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TargetStatus) DeepCopyInto(out *TargetStatus) {
*out = *in

View File

@ -97,9 +97,15 @@ func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.
switch target.BackupType {
case formolv1alpha1.OnlineKind:
// TODO: add a sidecar to the pod with the target.Containers[].Paths mounted
if err := r.AddOnlineSidecar(backupConf, target); err != nil {
if sidecarPaths, err := r.addOnlineSidecar(backupConf, target); err != nil {
r.Log.Error(err, "unable to add online sidecar")
return ctrl.Result{}, err
} else if len(sidecarPaths) > 0 {
backupConf.Status.Targets = append(backupConf.Status.Targets,
formolv1alpha1.TargetSidecarPath{
TargetName: target.TargetName,
SidecarPaths: sidecarPaths,
})
}
backupConf.Status.ActiveSidecar = true
case formolv1alpha1.JobKind:

View File

@ -24,9 +24,9 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"path/filepath"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
)
@ -178,11 +178,12 @@ func (r *BackupConfigurationReconciler) DeleteSidecar(backupConf formolv1alpha1.
return nil
}
func (r *BackupConfigurationReconciler) AddOnlineSidecar(backupConf formolv1alpha1.BackupConfiguration, target formolv1alpha1.Target) error {
addTags := func(sideCar *corev1.Container, podSpec *corev1.PodSpec, target formolv1alpha1.Target) bool {
func (r *BackupConfigurationReconciler) addOnlineSidecar(backupConf formolv1alpha1.BackupConfiguration, target formolv1alpha1.Target) (sidecarPaths []string, err error) {
addTags := func(sideCar *corev1.Container, podSpec *corev1.PodSpec, target formolv1alpha1.Target) ([]string, bool) {
var sidecarPaths []string
for i, container := range podSpec.Containers {
if container.Name == formolv1alpha1.SIDECARCONTAINER_NAME {
return false
return sidecarPaths, false
}
for _, targetContainer := range target.Containers {
if targetContainer.Name == container.Name {
@ -196,30 +197,34 @@ func (r *BackupConfigurationReconciler) AddOnlineSidecar(backupConf formolv1alph
// and mount them under a path that exists in the sidecar container
for i, path := range targetContainer.Paths {
vm := corev1.VolumeMount{ReadOnly: true}
var longest int = 0
var sidecarPath string
for _, volumeMount := range container.VolumeMounts {
var longest int = 0
if strings.HasPrefix(path, volumeMount.MountPath) && len(volumeMount.MountPath) > longest {
// if strings.HasPrefix(path, volumeMount.MountPath) && len(volumeMount.MountPath) > longest {
if rel, err := filepath.Rel(volumeMount.MountPath, path); err == nil && len(volumeMount.MountPath) > longest {
longest = len(volumeMount.MountPath)
vm.Name = volumeMount.Name
vm.MountPath = fmt.Sprintf("/backup%d", i)
vm.MountPath = fmt.Sprintf("/%s%d", formolv1alpha1.BACKUP_PREFIX_PATH, i)
vm.SubPath = volumeMount.SubPath
sidecarPath = filepath.Join(vm.MountPath, rel)
}
}
sideCar.VolumeMounts = append(sideCar.VolumeMounts, vm)
sidecarPaths = append(sidecarPaths, sidecarPath)
}
}
}
}
return true
return sidecarPaths, true
}
repo := formolv1alpha1.Repo{}
if err := r.Get(r.Context, client.ObjectKey{
if err = r.Get(r.Context, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: backupConf.Spec.Repository,
}, &repo); err != nil {
r.Log.Error(err, "unable to get Repo")
return err
return
}
r.Log.V(1).Info("Got Repository", "repo", repo)
env := repo.GetResticEnv(backupConf)
@ -245,33 +250,34 @@ func (r *BackupConfigurationReconciler) AddOnlineSidecar(backupConf formolv1alph
switch target.TargetKind {
case formolv1alpha1.Deployment:
deployment := &appsv1.Deployment{}
if err := r.Get(r.Context, client.ObjectKey{
if err = r.Get(r.Context, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: target.TargetName,
}, deployment); err != nil {
r.Log.Error(err, "cannot get deployment", "Deployment", target.TargetName)
return err
return
}
if addTags(&sideCar, &deployment.Spec.Template.Spec, target) {
if err := r.createRBACSidecar(corev1.ServiceAccount{
if paths, add := addTags(&sideCar, &deployment.Spec.Template.Spec, target); add == true {
sidecarPaths = paths
if err = r.createRBACSidecar(corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Namespace: deployment.Namespace,
Name: deployment.Spec.Template.Spec.ServiceAccountName,
},
}); err != nil {
r.Log.Error(err, "unable to create RBAC for the sidecar container")
return err
return
}
deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, sideCar)
r.Log.V(1).Info("Updating deployment", "deployment", deployment, "containers", deployment.Spec.Template.Spec.Containers)
if err := r.Update(r.Context, deployment); err != nil {
if err = r.Update(r.Context, deployment); err != nil {
r.Log.Error(err, "cannot update deployment", "Deployment", deployment)
return err
return
}
}
}
return nil
return
}
func (r *BackupConfigurationReconciler) createRBACSidecar(sa corev1.ServiceAccount) error {