mirror of
https://github.com/stakater/Reloader.git
synced 2026-08-20 04:26:28 +00:00
108 lines
3.1 KiB
Go
108 lines
3.1 KiB
Go
package workload
|
|
|
|
import (
|
|
"context"
|
|
|
|
batchv1 "k8s.io/api/batch/v1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/errors"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
)
|
|
|
|
// jobAccessor implements PodTemplateAccessor for Job.
|
|
type jobAccessor struct {
|
|
job *batchv1.Job
|
|
}
|
|
|
|
func (a *jobAccessor) GetPodTemplateSpec() *corev1.PodTemplateSpec {
|
|
return &a.job.Spec.Template
|
|
}
|
|
|
|
func (a *jobAccessor) GetObjectMeta() *metav1.ObjectMeta {
|
|
return &a.job.ObjectMeta
|
|
}
|
|
|
|
// JobWorkload wraps a Kubernetes Job.
|
|
// Note: Jobs have a special update mechanism - instead of updating the Job,
|
|
// Reloader deletes and recreates it with the same spec.
|
|
type JobWorkload struct {
|
|
*BaseWorkload[*batchv1.Job]
|
|
}
|
|
|
|
// NewJobWorkload creates a new JobWorkload.
|
|
func NewJobWorkload(j *batchv1.Job) *JobWorkload {
|
|
original := j.DeepCopy()
|
|
accessor := &jobAccessor{job: j}
|
|
return &JobWorkload{
|
|
BaseWorkload: NewBaseWorkload(j, original, accessor, KindJob),
|
|
}
|
|
}
|
|
|
|
// Ensure JobWorkload implements Workload.
|
|
var _ Workload = (*JobWorkload)(nil)
|
|
|
|
// Update for Job is a no-op - use PerformSpecialUpdate instead.
|
|
// Jobs trigger reloads by being deleted and recreated.
|
|
func (w *JobWorkload) Update(ctx context.Context, c client.Client) error {
|
|
// Jobs don't get updated directly - they are deleted and recreated
|
|
// This is handled by PerformSpecialUpdate
|
|
return nil
|
|
}
|
|
|
|
// ResetOriginal is a no-op for Jobs since they don't use strategic merge patch.
|
|
// Jobs are deleted and recreated instead of being patched.
|
|
func (w *JobWorkload) ResetOriginal() {}
|
|
|
|
func (w *JobWorkload) UpdateStrategy() UpdateStrategy {
|
|
return UpdateStrategyRecreate
|
|
}
|
|
|
|
// PerformSpecialUpdate deletes the Job and recreates it with the updated spec.
|
|
// This is necessary because Jobs are immutable after creation.
|
|
func (w *JobWorkload) PerformSpecialUpdate(ctx context.Context, c client.Client) (bool, error) {
|
|
oldJob := w.Object()
|
|
newJob := oldJob.DeepCopy()
|
|
|
|
// Delete the old job with background propagation
|
|
policy := metav1.DeletePropagationBackground
|
|
if err := c.Delete(ctx, oldJob, &client.DeleteOptions{
|
|
PropagationPolicy: &policy,
|
|
}); err != nil {
|
|
if !errors.IsNotFound(err) {
|
|
return false, err
|
|
}
|
|
}
|
|
|
|
// Clear fields that should not be specified when creating a new Job
|
|
newJob.ResourceVersion = ""
|
|
newJob.UID = ""
|
|
newJob.CreationTimestamp = metav1.Time{}
|
|
newJob.Status = batchv1.JobStatus{}
|
|
|
|
// Remove problematic labels that are auto-generated
|
|
delete(newJob.Spec.Template.Labels, "controller-uid")
|
|
delete(newJob.Spec.Template.Labels, batchv1.ControllerUidLabel)
|
|
delete(newJob.Spec.Template.Labels, batchv1.JobNameLabel)
|
|
delete(newJob.Spec.Template.Labels, "job-name")
|
|
|
|
// Remove the selector to allow it to be auto-generated
|
|
newJob.Spec.Selector = nil
|
|
|
|
// Create the new job with same spec
|
|
if err := c.Create(ctx, newJob, client.FieldOwner(FieldManager)); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func (w *JobWorkload) DeepCopy() Workload {
|
|
return NewJobWorkload(w.Object().DeepCopy())
|
|
}
|
|
|
|
// GetJob returns the underlying Job for special handling.
|
|
func (w *JobWorkload) GetJob() *batchv1.Job {
|
|
return w.Object()
|
|
}
|