Skip to content

Commit

Permalink
ETCD-695: Add job parallelism to recurrent backups
Browse files Browse the repository at this point in the history
  • Loading branch information
Elbehery committed Dec 28, 2024
1 parent cee7f9b commit efbaa09
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 11 deletions.
7 changes: 4 additions & 3 deletions pkg/cmd/request-backup/requestbackup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ package requestbackup

import (
"context"
goflag "flag"
"fmt"
"os"
"os/signal"
"syscall"

"github.com/openshift/cluster-etcd-operator/pkg/operator/operatorclient"
goflag "flag"

operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1"
operatorversionedclientv1alpha1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1alpha1"
"github.com/openshift/cluster-etcd-operator/pkg/operator/operatorclient"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utilrand "k8s.io/apimachinery/pkg/util/rand"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
)
Expand Down Expand Up @@ -143,7 +144,7 @@ func (r *requestBackupOpts) Run(ctx context.Context) error {
// like we usually do for other manifests?
etcdBackup := &operatorv1alpha1.EtcdBackup{
ObjectMeta: metav1.ObjectMeta{
Name: r.etcdBackupName,
Name: fmt.Sprintf("%s-%s", r.etcdBackupName, utilrand.String(8)),
Namespace: operatorclient.TargetNamespace,
// Due to a limitation of the kube-controller, we can't rely on the api to garbage collect non-namespaced
// etcdbackups from their corresponding namespaced jobs.
Expand Down
28 changes: 27 additions & 1 deletion pkg/operator/backupcontroller/backupcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package backupcontroller
import (
"context"
"fmt"
"k8s.io/utils/ptr"
"sort"
"strings"
"time"
Expand Down Expand Up @@ -176,6 +177,10 @@ func validateBackup(ctx context.Context,
kubeClient kubernetes.Interface,
backupsClient operatorv1alpha1client.EtcdBackupInterface) (bool, error) {

if backup.Spec.PVCName == "no-config" {
return true, nil
}

_, err := kubeClient.CoreV1().PersistentVolumeClaims(operatorclient.TargetNamespace).Get(ctx, backup.Spec.PVCName, metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
Expand Down Expand Up @@ -438,7 +443,11 @@ func createBackupJob(ctx context.Context,
}

if !injected {
return fmt.Errorf("could not inject PVC into Job template, please check the included cluster-backup-job.yaml")
if backup.Spec.PVCName == "no-config" {
useHostPathVol(job)
} else {
return fmt.Errorf("could not inject PVC into Job template, please check the included cluster-backup-job.yaml")
}
}

klog.Infof("BackupController starts with backup [%s] as job [%s], writing to filename [%s]", backup.Name, job.Name, backupFileName)
Expand Down Expand Up @@ -470,3 +479,20 @@ func createBackupJob(ctx context.Context,

return nil
}

func useHostPathVol(job *batchv1.Job) *batchv1.Job {

job.Spec.Template.Spec.Volumes = []corev1.Volume{
{
Name: "etc-kubernetes-cluster-backup",
VolumeSource: corev1.VolumeSource{
HostPath: &corev1.HostPathVolumeSource{
Path: "/etc/kubernetes/cluster-backup",
Type: ptr.To(corev1.HostPathDirectoryOrCreate),
},
},
},
}

return job
}
87 changes: 80 additions & 7 deletions pkg/operator/periodicbackupcontroller/periodicbackupcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package periodicbackupcontroller
import (
"context"
"fmt"
"k8s.io/utils/ptr"
"time"

clientv1 "k8s.io/client-go/listers/core/v1"
Expand Down Expand Up @@ -31,9 +32,8 @@ import (
)

const (
backupJobLabel = "backup-name"
defaultBackupCRName = "default"
etcdBackupServerContainerName = "etcd-backup-server"
backupJobLabel = "backup-name"
defaultBackupCRName = "default"
)

type PeriodicBackupController struct {
Expand Down Expand Up @@ -160,7 +160,14 @@ func reconcileCronJob(ctx context.Context,
}

if !injected {
return fmt.Errorf("could not inject PVC into CronJob template, please check the included cluster-backup-cronjob.yaml")
if backup.Name == defaultBackupCRName {
cronJob, err = applyAutomatedNoConfigBackup(cronJob)
if err != nil {
return err
}
} else {
return fmt.Errorf("could not inject PVC into CronJob template, please check the included cluster-backup-cronjob.yaml")
}
}

cronJob.Spec.Schedule = backup.Spec.EtcdBackupSpec.Schedule
Expand All @@ -182,9 +189,16 @@ func reconcileCronJob(ctx context.Context,
// The name of the CR will need to be unique for each scheduled run of the CronJob, so the name is
// set at runtime as the pod via the MY_POD_NAME populated via the downward API.
// See the CronJob template manifest for reference.
cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args = []string{
"request-backup",
"--pvc-name=" + backup.Spec.EtcdBackupSpec.PVCName,
if injected {
cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args = []string{
"request-backup",
"--pvc-name=" + backup.Spec.EtcdBackupSpec.PVCName,
}
} else {
cronJob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args = []string{
"request-backup",
"--pvc-name=" + "no-config",
}
}

if create {
Expand Down Expand Up @@ -272,3 +286,62 @@ func newCronJob() (*batchv1.CronJob, error) {

return obj.(*batchv1.CronJob), nil
}

func applyAutomatedNoConfigBackup(cronJob *batchv1.CronJob) (*batchv1.CronJob, error) {
if cronJob == nil {
return nil, fmt.Errorf("cronJob can not be nil")
}

// add job parallelism
cronJob.Spec.JobTemplate.Spec.Parallelism = ptr.To(int32(3))
cronJob.Spec.JobTemplate.Spec.Completions = ptr.To(int32(3))

cronJob.Spec.JobTemplate.Spec.Template.Spec.Affinity = &corev1.Affinity{
NodeAffinity: &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: []corev1.NodeSelectorTerm{
{
MatchExpressions: []corev1.NodeSelectorRequirement{
{
Key: "node-role.kubernetes.io/master",
Operator: corev1.NodeSelectorOpExists,
},
},
},
},
},
},

PodAntiAffinity: &corev1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []corev1.PodAffinityTerm{
{
LabelSelector: &v1.LabelSelector{
MatchExpressions: []v1.LabelSelectorRequirement{
{
Key: "app",
Operator: v1.LabelSelectorOpIn,
Values: []string{"cluster-backup-cronjob"},
},
},
},
TopologyKey: "kubernetes.io/hostname",
},
},
},
}

// add hostPath per job
cronJob.Spec.JobTemplate.Spec.Template.Spec.Volumes = []corev1.Volume{
{
Name: "etc-kubernetes-cluster-backup",
VolumeSource: corev1.VolumeSource{
HostPath: &corev1.HostPathVolumeSource{
Path: "/etc/kubernetes/cluster-backup",
Type: ptr.To(corev1.HostPathDirectoryOrCreate),
},
},
},
}

return cronJob, nil
}

0 comments on commit efbaa09

Please sign in to comment.