Compare commits

..

No commits in common. "3790f30e29c43c585d6cf2aed9e86a533c967baa" and "b330e2cfdde8e33488c5ed16fe6fab5cfe373942" have entirely different histories.

6 changed files with 69 additions and 151 deletions

View File

@ -38,10 +38,7 @@ const (
JobKind BackupType = "Job"
)
const (
BACKUP_PREFIX_PATH = `backup`
FORMOL_SHARED_VOLUME = `formol-shared`
)
const BACKUP_PREFIX_PATH = `backup`
type Step struct {
Name string `json:"name"`
@ -50,13 +47,9 @@ type Step struct {
}
type TargetContainer struct {
Name string `json:"name"`
// +optional
Name string `json:"name"`
Paths []string `json:"paths,omitempty"`
// +optional
Steps []Step `json:"steps,omitempty"`
// +kubebuilder:default:=/formol-shared
SharePath string `json:"sharePath"`
Steps []Step `json:"steps,omitempty"`
}
type Target struct {

View File

@ -40,8 +40,7 @@ type S3 struct {
}
type Local struct {
//corev1.VolumeSource `json:"source"`
corev1.VolumeSource `json:",inline"`
corev1.VolumeSource `json:"source"`
}
type Backend struct {

View File

@ -95,11 +95,18 @@ func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req ctrl.
}
for _, target := range backupConf.Spec.Targets {
if err := r.addSidecar(backupConf, target); err != nil {
r.Log.Error(err, "unable to add online sidecar")
return ctrl.Result{}, err
switch target.BackupType {
case formolv1alpha1.OnlineKind:
if err := r.addOnlineSidecar(backupConf, target); err != nil {
r.Log.Error(err, "unable to add online sidecar")
return ctrl.Result{}, err
}
backupConf.Status.ActiveSidecar = true
case formolv1alpha1.JobKind:
// TODO: add a sidecar to the pod with a shared volume
case formolv1alpha1.SnapshotKind:
// TODO: add a sidecar to run the steps
}
backupConf.Status.ActiveSidecar = true
}
if err := r.Status().Update(ctx, &backupConf); err != nil {

View File

@ -175,48 +175,25 @@ func (r *BackupConfigurationReconciler) DeleteSidecar(backupConf formolv1alpha1.
targetObject = &deployment
targetPodSpec = &deployment.Spec.Template.Spec
case formolv1alpha1.StatefulSet:
statefulSet := appsv1.StatefulSet{}
if err := r.Get(r.Context, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: target.TargetName,
}, &statefulSet); err != nil {
r.Log.Error(err, "cannot get deployment", "Deployment", target.TargetName)
return err
}
targetObject = &statefulSet
targetPodSpec = &statefulSet.Spec.Template.Spec
}
restoreContainers := []corev1.Container{}
for _, container := range targetPodSpec.Containers {
if container.Name == formolv1alpha1.SIDECARCONTAINER_NAME {
continue
}
restoreVms := []corev1.VolumeMount{}
for _, vm := range container.VolumeMounts {
if vm.Name == formolv1alpha1.FORMOL_SHARED_VOLUME {
r.Log.V(0).Info("cleanup VolumeMounts", "container", container.Name, "VolumeMount", vm.Name)
continue
}
restoreVms = append(restoreVms, vm)
}
r.Log.V(0).Info("cleanup VolumeMounts", "container", container.Name, "restoreVms", restoreVms)
container.VolumeMounts = restoreVms
restoreContainers = append(restoreContainers, container)
}
targetPodSpec.Containers = restoreContainers
restoreVolumes := []corev1.Volume{}
for _, volume := range targetPodSpec.Volumes {
if volume.Name == formolv1alpha1.RESTIC_REPO_VOLUME {
continue
if repo.Spec.Backend.Local != nil {
restoreVolumes := []corev1.Volume{}
for _, volume := range targetPodSpec.Volumes {
if volume.Name == formolv1alpha1.RESTIC_REPO_VOLUME {
continue
}
restoreVolumes = append(restoreVolumes, volume)
}
if volume.Name == formolv1alpha1.FORMOL_SHARED_VOLUME {
continue
}
restoreVolumes = append(restoreVolumes, volume)
targetPodSpec.Volumes = restoreVolumes
}
targetPodSpec.Volumes = restoreVolumes
removeTags(targetPodSpec, target)
if err := r.Update(r.Context, targetObject); err != nil {
r.Log.Error(err, "unable to remove sidecar", "targetObject", targetObject)
@ -236,7 +213,42 @@ func hasSidecar(podSpec *corev1.PodSpec) bool {
return false
}
func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.BackupConfiguration, target formolv1alpha1.Target) (err error) {
func (r *BackupConfigurationReconciler) addOnlineSidecar(backupConf formolv1alpha1.BackupConfiguration, target formolv1alpha1.Target) (err error) {
addTags := func(podSpec *corev1.PodSpec, target formolv1alpha1.Target) (sidecarPaths []string, vms []corev1.VolumeMount) {
for i, container := range podSpec.Containers {
for _, targetContainer := range target.Containers {
if targetContainer.Name == container.Name {
// Found a target container. Tag it.
podSpec.Containers[i].Env = append(container.Env, corev1.EnvVar{
Name: formolv1alpha1.TARGETCONTAINER_TAG,
Value: container.Name,
})
// targetContainer.Paths are the paths to backup
// We have to find what volumes are mounted under those paths
// 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 {
// 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("/%s%d", formolv1alpha1.BACKUP_PREFIX_PATH, i)
vm.SubPath = volumeMount.SubPath
sidecarPath = filepath.Join(vm.MountPath, rel)
}
}
vms = append(vms, vm)
sidecarPaths = append(sidecarPaths, sidecarPath)
}
}
}
}
return
}
repo := formolv1alpha1.Repo{}
if err = r.Get(r.Context, client.ObjectKey{
Namespace: backupConf.Namespace,
@ -280,17 +292,6 @@ func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.Bac
}
targetObject = &deployment
targetPodSpec = &deployment.Spec.Template.Spec
case formolv1alpha1.StatefulSet:
statefulSet := appsv1.StatefulSet{}
if err = r.Get(r.Context, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: target.TargetName,
}, &statefulSet); err != nil {
r.Log.Error(err, "cannot get deployment", "Deployment", target.TargetName)
return
}
targetObject = &statefulSet
targetPodSpec = &statefulSet.Spec.Template.Spec
}
if !hasSidecar(targetPodSpec) {
if err = r.createRBACSidecar(corev1.ServiceAccount{
@ -302,19 +303,13 @@ func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.Bac
r.Log.Error(err, "unable to create RBAC for the sidecar container")
return
}
switch target.BackupType {
case formolv1alpha1.OnlineKind:
sidecarPaths, vms := addOnlineSidecarTags(targetPodSpec, target)
sidecar.Env = append(sidecar.Env, corev1.EnvVar{
Name: formolv1alpha1.BACKUP_PATHS,
Value: strings.Join(sidecarPaths, string(os.PathListSeparator)),
})
sidecar.VolumeMounts = vms
case formolv1alpha1.JobKind:
sidecar.VolumeMounts = addJobSidecarTags(targetPodSpec, target)
}
sidecarPaths, vms := addTags(targetPodSpec, target)
sidecar.Env = append(sidecar.Env, corev1.EnvVar{
Name: formolv1alpha1.BACKUP_PATHS,
Value: strings.Join(sidecarPaths, string(os.PathListSeparator)),
})
if repo.Spec.Backend.Local != nil {
sidecar.VolumeMounts = append(sidecar.VolumeMounts, corev1.VolumeMount{
sidecar.VolumeMounts = append(vms, corev1.VolumeMount{
Name: formolv1alpha1.RESTIC_REPO_VOLUME,
MountPath: formolv1alpha1.RESTIC_REPO_PATH,
})
@ -322,6 +317,8 @@ func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.Bac
Name: formolv1alpha1.RESTIC_REPO_VOLUME,
VolumeSource: repo.Spec.Backend.Local.VolumeSource,
})
} else {
sidecar.VolumeMounts = vms
}
// The sidecar definition is complete. Add it to the targetObject
@ -435,77 +432,3 @@ func (r *BackupConfigurationReconciler) createRBACSidecar(sa corev1.ServiceAccou
}
return nil
}
func addJobSidecarTags(podSpec *corev1.PodSpec, target formolv1alpha1.Target) (vms []corev1.VolumeMount) {
for i, container := range podSpec.Containers {
for _, targetContainer := range target.Containers {
if targetContainer.Name == container.Name {
// Found a target container. Tag it.
podSpec.Containers[i].Env = append(container.Env, corev1.EnvVar{
Name: formolv1alpha1.TARGETCONTAINER_TAG,
Value: container.Name,
})
// Create a shared mount between the target and sidecar container
// the output of the Job will be saved in the shared volume
// and restic will then backup the content of the volume
var addSharedVol bool = true
for _, vol := range podSpec.Volumes {
if vol.Name == formolv1alpha1.FORMOL_SHARED_VOLUME {
addSharedVol = false
}
}
if addSharedVol {
podSpec.Volumes = append(podSpec.Volumes,
corev1.Volume{
Name: formolv1alpha1.FORMOL_SHARED_VOLUME,
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
})
}
podSpec.Containers[i].VolumeMounts = append(podSpec.Containers[i].VolumeMounts, corev1.VolumeMount{
Name: formolv1alpha1.FORMOL_SHARED_VOLUME,
MountPath: targetContainer.SharePath,
})
vms = append(vms, corev1.VolumeMount{
Name: formolv1alpha1.FORMOL_SHARED_VOLUME,
MountPath: targetContainer.SharePath,
})
}
}
}
return
}
func addOnlineSidecarTags(podSpec *corev1.PodSpec, target formolv1alpha1.Target) (sidecarPaths []string, vms []corev1.VolumeMount) {
for i, container := range podSpec.Containers {
for _, targetContainer := range target.Containers {
if targetContainer.Name == container.Name {
// Found a target container. Tag it.
podSpec.Containers[i].Env = append(container.Env, corev1.EnvVar{
Name: formolv1alpha1.TARGETCONTAINER_TAG,
Value: container.Name,
})
// targetContainer.Paths are the paths to backup
// We have to find what volumes are mounted under those paths
// 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 {
// 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("/%s%d", formolv1alpha1.BACKUP_PREFIX_PATH, i)
vm.SubPath = volumeMount.SubPath
sidecarPath = filepath.Join(vm.MountPath, rel)
}
}
vms = append(vms, vm)
sidecarPaths = append(sidecarPaths, sidecarPath)
}
}
}
}
return
}

View File

@ -79,7 +79,8 @@ metadata:
spec:
backend:
local:
emptyDir:
source:
emptyDir:
repositorySecrets: secret-minio
---
apiVersion: formol.desmojim.fr/v1alpha1

View File

@ -27,11 +27,6 @@ spec:
finalize: true
paths:
- /data
- backupType: Job
targetKind: StatefulSet
targetName: postgres-demo
containers:
- name: postgres
# - kind: Job
# name: backup-pg
# steps: