|
|
|
|
@ -175,25 +175,48 @@ 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
|
|
|
|
|
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)
|
|
|
|
|
restoreVolumes := []corev1.Volume{}
|
|
|
|
|
for _, volume := range targetPodSpec.Volumes {
|
|
|
|
|
if volume.Name == formolv1alpha1.RESTIC_REPO_VOLUME {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
targetPodSpec.Volumes = restoreVolumes
|
|
|
|
|
if volume.Name == formolv1alpha1.FORMOL_SHARED_VOLUME {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
restoreVolumes = append(restoreVolumes, volume)
|
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
@ -213,42 +236,7 @@ func hasSidecar(podSpec *corev1.PodSpec) bool {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *BackupConfigurationReconciler) addSidecar(backupConf formolv1alpha1.BackupConfiguration, target formolv1alpha1.Target) (err error) {
|
|
|
|
|
repo := formolv1alpha1.Repo{}
|
|
|
|
|
if err = r.Get(r.Context, client.ObjectKey{
|
|
|
|
|
Namespace: backupConf.Namespace,
|
|
|
|
|
@ -292,6 +280,17 @@ func (r *BackupConfigurationReconciler) addOnlineSidecar(backupConf formolv1alph
|
|
|
|
|
}
|
|
|
|
|
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{
|
|
|
|
|
@ -303,13 +302,19 @@ func (r *BackupConfigurationReconciler) addOnlineSidecar(backupConf formolv1alph
|
|
|
|
|
r.Log.Error(err, "unable to create RBAC for the sidecar container")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
sidecarPaths, vms := addTags(targetPodSpec, target)
|
|
|
|
|
sidecar.Env = append(sidecar.Env, corev1.EnvVar{
|
|
|
|
|
Name: formolv1alpha1.BACKUP_PATHS,
|
|
|
|
|
Value: strings.Join(sidecarPaths, string(os.PathListSeparator)),
|
|
|
|
|
})
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
if repo.Spec.Backend.Local != nil {
|
|
|
|
|
sidecar.VolumeMounts = append(vms, corev1.VolumeMount{
|
|
|
|
|
sidecar.VolumeMounts = append(sidecar.VolumeMounts, corev1.VolumeMount{
|
|
|
|
|
Name: formolv1alpha1.RESTIC_REPO_VOLUME,
|
|
|
|
|
MountPath: formolv1alpha1.RESTIC_REPO_PATH,
|
|
|
|
|
})
|
|
|
|
|
@ -317,8 +322,6 @@ func (r *BackupConfigurationReconciler) addOnlineSidecar(backupConf formolv1alph
|
|
|
|
|
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
|
|
|
|
|
@ -432,3 +435,77 @@ 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
|
|
|
|
|
}
|
|
|
|
|
|