Handle sidecar creation for the Job backup type with shared volume

This commit is contained in:
Jean-Marc ANDRE 2023-02-24 21:49:02 +01:00
parent 6b0add3fdf
commit 3790f30e29
5 changed files with 97 additions and 12 deletions

View File

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

View File

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

View File

@ -175,25 +175,48 @@ func (r *BackupConfigurationReconciler) DeleteSidecar(backupConf formolv1alpha1.
targetObject = &deployment targetObject = &deployment
targetPodSpec = &deployment.Spec.Template.Spec 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{} restoreContainers := []corev1.Container{}
for _, container := range targetPodSpec.Containers { for _, container := range targetPodSpec.Containers {
if container.Name == formolv1alpha1.SIDECARCONTAINER_NAME { if container.Name == formolv1alpha1.SIDECARCONTAINER_NAME {
continue 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) restoreContainers = append(restoreContainers, container)
} }
targetPodSpec.Containers = restoreContainers targetPodSpec.Containers = restoreContainers
if repo.Spec.Backend.Local != nil { restoreVolumes := []corev1.Volume{}
restoreVolumes := []corev1.Volume{} for _, volume := range targetPodSpec.Volumes {
for _, volume := range targetPodSpec.Volumes { if volume.Name == formolv1alpha1.RESTIC_REPO_VOLUME {
if volume.Name == formolv1alpha1.RESTIC_REPO_VOLUME { continue
continue
}
restoreVolumes = append(restoreVolumes, volume)
} }
targetPodSpec.Volumes = restoreVolumes if volume.Name == formolv1alpha1.FORMOL_SHARED_VOLUME {
continue
}
restoreVolumes = append(restoreVolumes, volume)
} }
targetPodSpec.Volumes = restoreVolumes
removeTags(targetPodSpec, target) removeTags(targetPodSpec, target)
if err := r.Update(r.Context, targetObject); err != nil { if err := r.Update(r.Context, targetObject); err != nil {
r.Log.Error(err, "unable to remove sidecar", "targetObject", targetObject) r.Log.Error(err, "unable to remove sidecar", "targetObject", targetObject)
@ -257,6 +280,17 @@ func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.Bac
} }
targetObject = &deployment targetObject = &deployment
targetPodSpec = &deployment.Spec.Template.Spec 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 !hasSidecar(targetPodSpec) {
if err = r.createRBACSidecar(corev1.ServiceAccount{ if err = r.createRBACSidecar(corev1.ServiceAccount{
@ -276,6 +310,8 @@ func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.Bac
Value: strings.Join(sidecarPaths, string(os.PathListSeparator)), Value: strings.Join(sidecarPaths, string(os.PathListSeparator)),
}) })
sidecar.VolumeMounts = vms sidecar.VolumeMounts = vms
case formolv1alpha1.JobKind:
sidecar.VolumeMounts = addJobSidecarTags(targetPodSpec, target)
} }
if repo.Spec.Backend.Local != nil { if repo.Spec.Backend.Local != nil {
sidecar.VolumeMounts = append(sidecar.VolumeMounts, corev1.VolumeMount{ sidecar.VolumeMounts = append(sidecar.VolumeMounts, corev1.VolumeMount{
@ -400,6 +436,45 @@ func (r *BackupConfigurationReconciler) createRBACSidecar(sa corev1.ServiceAccou
return nil 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) { func addOnlineSidecarTags(podSpec *corev1.PodSpec, target formolv1alpha1.Target) (sidecarPaths []string, vms []corev1.VolumeMount) {
for i, container := range podSpec.Containers { for i, container := range podSpec.Containers {
for _, targetContainer := range target.Containers { for _, targetContainer := range target.Containers {

View File

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

View File

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