Add cluster_labels and annotations to logical backup CronJob and Jobs (#3085)
* Add cluster_labels and annotations to logical backup CronJob and Jobs When using the logical backup feature, the CronJob and its created Jobs were missing the cluster_labels and annotations that are applied to other cluster resources. This made it difficult to filter or identify backup jobs using the same labels as other cluster components. Changes: - Added ObjectMeta with labels and annotations to JobTemplateSpec - Updated CronJob ObjectMeta to use the merged labels (including 'application: spilo-logical-backup') - Updated tests to expect the new labels
This commit is contained in:
parent
f0b5d3725c
commit
873dd548ff
|
|
@ -240,7 +240,7 @@ class K8s:
|
||||||
time.sleep(self.RETRY_TIMEOUT_SEC)
|
time.sleep(self.RETRY_TIMEOUT_SEC)
|
||||||
|
|
||||||
def get_logical_backup_job(self, namespace='default'):
|
def get_logical_backup_job(self, namespace='default'):
|
||||||
return self.api.batch_v1.list_namespaced_cron_job(namespace, label_selector="application=spilo")
|
return self.api.batch_v1.list_namespaced_cron_job(namespace, label_selector="application=spilo-logical-backup")
|
||||||
|
|
||||||
def wait_for_logical_backup_job(self, expected_num_of_jobs):
|
def wait_for_logical_backup_job(self, expected_num_of_jobs):
|
||||||
while (len(self.get_logical_backup_job().items) != expected_num_of_jobs):
|
while (len(self.get_logical_backup_job().items) != expected_num_of_jobs):
|
||||||
|
|
|
||||||
|
|
@ -893,6 +893,16 @@ func (c *Cluster) compareLogicalBackupJob(cur, new *batchv1.CronJob) *compareLog
|
||||||
reasons = append(reasons, fmt.Sprintf("new job's env PG_VERSION %q does not match the current one %q", newPgVersion, curPgVersion))
|
reasons = append(reasons, fmt.Sprintf("new job's env PG_VERSION %q does not match the current one %q", newPgVersion, curPgVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(cur.Labels, new.Labels) {
|
||||||
|
match = false
|
||||||
|
reasons = append(reasons, "new job's labels do not match the current ones")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(cur.Spec.JobTemplate.Labels, new.Spec.JobTemplate.Labels) {
|
||||||
|
match = false
|
||||||
|
reasons = append(reasons, "new job's template labels do not match the current ones")
|
||||||
|
}
|
||||||
|
|
||||||
needsReplace := false
|
needsReplace := false
|
||||||
contReasons := make([]string, 0)
|
contReasons := make([]string, 0)
|
||||||
needsReplace, contReasons = c.compareContainers("cronjob container", cur.Spec.JobTemplate.Spec.Template.Spec.Containers, new.Spec.JobTemplate.Spec.Template.Spec.Containers, needsReplace, contReasons)
|
needsReplace, contReasons = c.compareContainers("cronjob container", cur.Spec.JobTemplate.Spec.Template.Spec.Containers, new.Spec.JobTemplate.Spec.Template.Spec.Containers, needsReplace, contReasons)
|
||||||
|
|
|
||||||
|
|
@ -2414,6 +2414,10 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1.CronJob, error) {
|
||||||
// configure a cron job
|
// configure a cron job
|
||||||
|
|
||||||
jobTemplateSpec := batchv1.JobTemplateSpec{
|
jobTemplateSpec := batchv1.JobTemplateSpec{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Labels: labels,
|
||||||
|
Annotations: c.annotationsSet(annotations),
|
||||||
|
},
|
||||||
Spec: jobSpec,
|
Spec: jobSpec,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2426,8 +2430,8 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1.CronJob, error) {
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: c.getLogicalBackupJobName(),
|
Name: c.getLogicalBackupJobName(),
|
||||||
Namespace: c.Namespace,
|
Namespace: c.Namespace,
|
||||||
Labels: c.labelsSet(true),
|
Labels: labels,
|
||||||
Annotations: c.annotationsSet(nil),
|
Annotations: c.annotationsSet(annotations),
|
||||||
OwnerReferences: c.ownerReferences(),
|
OwnerReferences: c.ownerReferences(),
|
||||||
},
|
},
|
||||||
Spec: batchv1.CronJobSpec{
|
Spec: batchv1.CronJobSpec{
|
||||||
|
|
|
||||||
|
|
@ -3875,7 +3875,7 @@ func TestGenerateLogicalBackupJob(t *testing.T) {
|
||||||
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("100Mi")},
|
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("100Mi")},
|
||||||
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("500Mi")},
|
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("500Mi")},
|
||||||
},
|
},
|
||||||
expectedLabel: map[string]string{configResources.ClusterNameLabel: clusterName, "team": teamId},
|
expectedLabel: map[string]string{"application": "spilo-logical-backup", configResources.ClusterNameLabel: clusterName, "team": teamId},
|
||||||
expectedAnnotation: nil,
|
expectedAnnotation: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -3900,7 +3900,7 @@ func TestGenerateLogicalBackupJob(t *testing.T) {
|
||||||
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("10m"), Memory: k8sutil.StringToPointer("50Mi")},
|
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("10m"), Memory: k8sutil.StringToPointer("50Mi")},
|
||||||
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("300m"), Memory: k8sutil.StringToPointer("300Mi")},
|
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("300m"), Memory: k8sutil.StringToPointer("300Mi")},
|
||||||
},
|
},
|
||||||
expectedLabel: map[string]string{configResources.ClusterNameLabel: clusterName, "team": teamId},
|
expectedLabel: map[string]string{"application": "spilo-logical-backup", configResources.ClusterNameLabel: clusterName, "team": teamId},
|
||||||
expectedAnnotation: nil,
|
expectedAnnotation: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -3923,7 +3923,7 @@ func TestGenerateLogicalBackupJob(t *testing.T) {
|
||||||
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("50m"), Memory: k8sutil.StringToPointer("100Mi")},
|
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("50m"), Memory: k8sutil.StringToPointer("100Mi")},
|
||||||
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("250m"), Memory: k8sutil.StringToPointer("500Mi")},
|
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("250m"), Memory: k8sutil.StringToPointer("500Mi")},
|
||||||
},
|
},
|
||||||
expectedLabel: map[string]string{configResources.ClusterNameLabel: clusterName, "team": teamId},
|
expectedLabel: map[string]string{"application": "spilo-logical-backup", configResources.ClusterNameLabel: clusterName, "team": teamId},
|
||||||
expectedAnnotation: nil,
|
expectedAnnotation: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -3946,7 +3946,7 @@ func TestGenerateLogicalBackupJob(t *testing.T) {
|
||||||
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("200Mi")},
|
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("200Mi")},
|
||||||
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("200Mi")},
|
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("200Mi")},
|
||||||
},
|
},
|
||||||
expectedLabel: map[string]string{configResources.ClusterNameLabel: clusterName, "team": teamId},
|
expectedLabel: map[string]string{"application": "spilo-logical-backup", configResources.ClusterNameLabel: clusterName, "team": teamId},
|
||||||
expectedAnnotation: nil,
|
expectedAnnotation: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -3968,7 +3968,7 @@ func TestGenerateLogicalBackupJob(t *testing.T) {
|
||||||
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("100Mi")},
|
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("100Mi")},
|
||||||
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("500Mi")},
|
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("500Mi")},
|
||||||
},
|
},
|
||||||
expectedLabel: map[string]string{"labelKey": "labelValue", "cluster-name": clusterName, "team": teamId},
|
expectedLabel: map[string]string{"application": "spilo-logical-backup", "labelKey": "labelValue", "cluster-name": clusterName, "team": teamId},
|
||||||
expectedAnnotation: nil,
|
expectedAnnotation: nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -3990,7 +3990,7 @@ func TestGenerateLogicalBackupJob(t *testing.T) {
|
||||||
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("100Mi")},
|
ResourceRequests: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("100m"), Memory: k8sutil.StringToPointer("100Mi")},
|
||||||
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("500Mi")},
|
ResourceLimits: acidv1.ResourceDescription{CPU: k8sutil.StringToPointer("1"), Memory: k8sutil.StringToPointer("500Mi")},
|
||||||
},
|
},
|
||||||
expectedLabel: map[string]string{configResources.ClusterNameLabel: clusterName, "team": teamId},
|
expectedLabel: map[string]string{"application": "spilo-logical-backup", configResources.ClusterNameLabel: clusterName, "team": teamId},
|
||||||
expectedAnnotation: map[string]string{"annotationKey": "annotationValue"},
|
expectedAnnotation: map[string]string{"annotationKey": "annotationValue"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1769,6 +1769,16 @@ func (c *Cluster) syncLogicalBackupJob() error {
|
||||||
}
|
}
|
||||||
c.logger.Info("the logical backup job is synced")
|
c.logger.Info("the logical backup job is synced")
|
||||||
}
|
}
|
||||||
|
if !reflect.DeepEqual(job.Labels, desiredJob.Labels) {
|
||||||
|
patchData, err := metaLabelsPatch(desiredJob.Labels)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not form patch for the logical backup job %q labels: %v", jobName, err)
|
||||||
|
}
|
||||||
|
_, err = c.KubeClient.CronJobs(c.Namespace).Patch(context.TODO(), jobName, types.MergePatchType, []byte(patchData), metav1.PatchOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not patch labels of the logical backup job %q: %v", jobName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if changed, _ := c.compareAnnotations(job.Annotations, desiredJob.Annotations, nil); changed {
|
if changed, _ := c.compareAnnotations(job.Annotations, desiredJob.Annotations, nil); changed {
|
||||||
patchData, err := metaAnnotationsPatch(desiredJob.Annotations)
|
patchData, err := metaAnnotationsPatch(desiredJob.Annotations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,14 @@ func metaAnnotationsPatch(annotations map[string]string) ([]byte, error) {
|
||||||
}{&meta})
|
}{&meta})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func metaLabelsPatch(labels map[string]string) ([]byte, error) {
|
||||||
|
var meta metav1.ObjectMeta
|
||||||
|
meta.Labels = labels
|
||||||
|
return json.Marshal(struct {
|
||||||
|
ObjMeta interface{} `json:"metadata"`
|
||||||
|
}{&meta})
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cluster) logPDBChanges(old, new *policyv1.PodDisruptionBudget, isUpdate bool, reason string) {
|
func (c *Cluster) logPDBChanges(old, new *policyv1.PodDisruptionBudget, isUpdate bool, reason string) {
|
||||||
if isUpdate {
|
if isUpdate {
|
||||||
c.logger.Infof("pod disruption budget %q has been changed", util.NameFromMeta(old.ObjectMeta))
|
c.logger.Infof("pod disruption budget %q has been changed", util.NameFromMeta(old.ObjectMeta))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue