fix: properly suspend and resume k8s CronJob objects when executing scheduler-cron-write

This commit is contained in:
Jose Diaz-Gonzalez
2025-09-21 20:08:22 -04:00
parent c885205b91
commit 4a357e9896
4 changed files with 92 additions and 1 deletions

View File

@@ -1,5 +1,5 @@
SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/ensure-charts subcommands/initialize subcommands/labels:set subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
TRIGGERS = triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-is-deployed triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop
TRIGGERS = triggers/core-post-deploy triggers/core-post-extract triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-create triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-is-deployed triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop triggers/scheduler-cron-write
BUILD = commands subcommands triggers
PLUGIN_NAME = scheduler-k3s

View File

@@ -805,6 +805,35 @@ func (k KubernetesClient) ListTriggerAuthentications(ctx context.Context, input
return triggerAuthentications, nil
}
// ResumeCronJobsInput contains all the information needed to resume a Kubernetes cron job
type ResumeCronJobsInput struct {
// LabelSelector is the Kubernetes label selector
LabelSelector string
// Namespace is the Kubernetes namespace
Namespace string
}
// ResumeCronJobs resumes a Kubernetes cron job
func (k KubernetesClient) ResumeCronJobs(ctx context.Context, input ResumeCronJobsInput) error {
cronJobs, err := k.Client.BatchV1().CronJobs(input.Namespace).List(ctx, metav1.ListOptions{
LabelSelector: input.LabelSelector,
})
if err != nil {
return err
}
for _, cronJob := range cronJobs.Items {
cronJob.Spec.Suspend = ptr.To(false)
_, err := k.Client.BatchV1().CronJobs(input.Namespace).Update(ctx, &cronJob, metav1.UpdateOptions{})
if err != nil {
return err
}
}
return nil
}
// ScaleDeploymentInput contains all the information needed to scale a Kubernetes deployment
type ScaleDeploymentInput struct {
// Name is the Kubernetes deployment name

View File

@@ -123,6 +123,10 @@ func main() {
scheduler := flag.Arg(0)
appName := flag.Arg(1)
err = scheduler_k3s.TriggerSchedulerStop(scheduler, appName)
case "scheduler-cron-write":
scheduler := flag.Arg(0)
appName := flag.Arg(1)
err = scheduler_k3s.TriggerSchedulerCronWrite(scheduler, appName)
case "scheduler-post-delete":
scheduler := flag.Arg(0)
appName := flag.Arg(1)

View File

@@ -163,6 +163,64 @@ func TriggerSchedulerAppStatus(scheduler string, appName string) error {
return nil
}
// TriggerSchedulerCronWrite writes out cron entries for a given application
func TriggerSchedulerCronWrite(scheduler string, appName string) error {
if scheduler != "k3s" {
return nil
}
allCronEntries, err := cron.FetchCronEntries(cron.FetchCronEntriesInput{AppName: appName})
if err != nil {
return fmt.Errorf("Error fetching cron entries: %w", err)
}
ctx, cancel := context.WithCancel(context.Background())
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGQUIT,
syscall.SIGTERM)
go func() {
<-signals
common.LogWarn(fmt.Sprintf("Deployment of %s has been cancelled", appName))
cancel()
}()
namespace := getComputedNamespace(appName)
clientset, err := NewKubernetesClient()
if err != nil {
return fmt.Errorf("Error creating kubernetes client: %w", err)
}
for _, cronEntry := range allCronEntries {
labelSelector := []string{
fmt.Sprintf("app.kubernetes.io/part-of=%s", appName),
fmt.Sprintf("dokku.com/cron-id=%s", cronEntry.ID),
}
if cronEntry.Maintenance {
err = clientset.SuspendCronJobs(ctx, SuspendCronJobsInput{
Namespace: namespace,
LabelSelector: strings.Join(labelSelector, ","),
})
if err != nil {
return fmt.Errorf("Error suspending cron jobs: %w", err)
}
} else {
err = clientset.ResumeCronJobs(ctx, ResumeCronJobsInput{
Namespace: namespace,
LabelSelector: strings.Join(labelSelector, ","),
})
if err != nil {
return fmt.Errorf("Error resuming cron jobs: %w", err)
}
}
}
return nil
}
// TriggerSchedulerDeploy deploys an image tag for a given application
func TriggerSchedulerDeploy(scheduler string, appName string, imageTag string) error {
if scheduler != "k3s" {