diff --git a/create/application.go b/create/application.go index 7fa8c96c..0d4c7a57 100644 --- a/create/application.go +++ b/create/application.go @@ -94,6 +94,7 @@ type scheduledJob struct { Name string `help:"Name of the scheduled job job to add." placeholder:"scheduled-1"` Size *string `help:"Size (resources) of the scheduled job (defaults to \"${app_default_size}\")." placeholder:"${app_default_size}"` Schedule string `help:"Cron notation string for the scheduled job (defaults to \"* * * * *\")." placeholder:"\"* * * * *\""` + TimeZone *string `help:"Time zone the schedule is evaluated in, e.g. \"Europe/Zurich\" (defaults to \"UTC\")." placeholder:"Europe/Zurich"` Retries int32 `default:"${app_default_scheduled_job_retries}" help:"How many times the job will be restarted on failure. Default is ${app_default_scheduled_job_retries} and maximum 5."` Timeout time.Duration `default:"${app_default_scheduled_job_timeout}" help:"Timeout of the job. Default is ${app_default_scheduled_job_timeout}, minimum is 1 minute and maximum is 30 minutes."` } @@ -344,6 +345,9 @@ func (cmd *applicationCmd) config() apps.Config { if cmd.ScheduledJob.Size != nil { scheduledJob.Size = new(apps.ApplicationSize(*cmd.ScheduledJob.Size)) } + if cmd.ScheduledJob.TimeZone != nil { + scheduledJob.TimeZone = *cmd.ScheduledJob.TimeZone + } config.ScheduledJobs = append(config.ScheduledJobs, scheduledJob) } diff --git a/create/application_test.go b/create/application_test.go index 162ce8a5..2ce4a87c 100644 --- a/create/application_test.go +++ b/create/application_test.go @@ -136,6 +136,35 @@ func TestCreateApplication(t *testing.T) { is.Equal(*cmd.BasicAuth, *app.Spec.ForProvider.Config.EnableBasicAuth) }, }, + "with scheduled job": { + cmd: applicationCmd{ + ResourceCmd: ResourceCmd{ + Wait: false, + Name: "scheduled-job-app", + }, + Size: new("mini"), + ScheduledJob: scheduledJob{ + Name: "nightly-backup", + Command: "./backup.sh", + Schedule: "0 3 * * *", + TimeZone: new("Europe/Zurich"), + Retries: 2, + Timeout: 10 * time.Minute, + }, + SkipRepoAccessCheck: true, + }, + checkApp: func(t *testing.T, cmd applicationCmd, app *apps.Application) { + is := require.New(t) + is.Len(app.Spec.ForProvider.Config.ScheduledJobs, 1) + job := app.Spec.ForProvider.Config.ScheduledJobs[0] + is.Equal(cmd.ScheduledJob.Name, job.Name) + is.Equal(cmd.ScheduledJob.Command, job.Command) + is.Equal(cmd.ScheduledJob.Schedule, job.Schedule) + is.Equal(*cmd.ScheduledJob.TimeZone, job.TimeZone) + is.Equal(cmd.ScheduledJob.Retries, *job.Retries) + is.Equal(cmd.ScheduledJob.Timeout, job.Timeout.Duration) + }, + }, "with user/pass git auth": { cmd: applicationCmd{ Git: gitConfig{ diff --git a/update/application.go b/update/application.go index 89bc3362..fb35d157 100644 --- a/update/application.go +++ b/update/application.go @@ -49,22 +49,22 @@ type applicationCmd struct { // structs. Due to the usage of kong these pointers will never be `nil`. // So checking for `nil` values can not be used to find out if some of // the struct fields have been set. - DeployJob *deployJob `embed:"" prefix:"deploy-job-"` - WorkerJob *workerJob `embed:"" prefix:"worker-job-"` - ScheduledJob *scheduledJob `embed:"" prefix:"scheduled-job-"` - DeleteWorkerJob *string `help:"Delete a worker job by name."` - DeleteScheduledJob *string `help:"Delete a scheduled job by name."` + DeployJob *deployJob `embed:"" prefix:"deploy-job-"` + WorkerJob *workerJob `embed:"" prefix:"worker-job-"` + ScheduledJob *scheduledJob `embed:"" prefix:"scheduled-job-"` + DeleteWorkerJob *string `help:"Delete a worker job by name."` + DeleteScheduledJob *string `help:"Delete a scheduled job by name."` Service application.ServiceMap `help:"Service reference to add/update in the form name=kind/target-name."` - DeleteService []string `help:"Service reference names to remove."` - RetryRelease *bool `help:"Retries release for the application." placeholder:"false"` - RetryBuild *bool `help:"Retries build for the application if set to true." placeholder:"false"` - Pause *bool `negatable:"" help:"Pause or unpause the application. Pausing stops all costs."` - GitInformationServiceURL string `help:"URL of the git information service." default:"https://git-info.deplo.io" env:"GIT_INFORMATION_SERVICE_URL" hidden:""` - SkipRepoAccessCheck bool `help:"Skip the git repository access check." default:"false"` - Debug bool `help:"Enable debug messages." default:"false"` - Language *string `help:"${app_language_help} Possible values: ${enum}" enum:"ruby,php,python,golang,nodejs,static,"` - DockerfileBuild dockerfileBuild `embed:""` - BuildpackStack *string `help:"${app_buildpack_stack_help} Possible values: ${enum}" enum:"paketo,heroku,"` + DeleteService []string `help:"Service reference names to remove."` + RetryRelease *bool `help:"Retries release for the application." placeholder:"false"` + RetryBuild *bool `help:"Retries build for the application if set to true." placeholder:"false"` + Pause *bool `negatable:"" help:"Pause or unpause the application. Pausing stops all costs."` + GitInformationServiceURL string `help:"URL of the git information service." default:"https://git-info.deplo.io" env:"GIT_INFORMATION_SERVICE_URL" hidden:""` + SkipRepoAccessCheck bool `help:"Skip the git repository access check." default:"false"` + Debug bool `help:"Enable debug messages." default:"false"` + Language *string `help:"${app_language_help} Possible values: ${enum}" enum:"ruby,php,python,golang,nodejs,static,"` + DockerfileBuild dockerfileBuild `embed:""` + BuildpackStack *string `help:"${app_buildpack_stack_help} Possible values: ${enum}" enum:"paketo,heroku,"` } type gitConfig struct { @@ -126,12 +126,13 @@ type scheduledJob struct { Name *string `help:"Name of the scheduled job job to add." placeholder:"scheduled-1"` Size *string `help:"Size (resources) of the scheduled job (defaults to \"${app_default_size}\")." placeholder:"${app_default_size}"` Schedule *string `help:"Cron notation string for the scheduled job (defaults to \"* * * * *\")." placeholder:"\"* * * * *\""` + TimeZone *string `help:"Time zone the schedule is evaluated in, e.g. \"Europe/Zurich\" (defaults to \"UTC\")." placeholder:"Europe/Zurich"` Retries *int32 `help:"How many times the job will be restarted on failure." placeholder:"${app_default_scheduled_job_retries}"` Timeout *time.Duration `help:"Timeout of the job." placeholder:"${app_default_scheduled_job_timeout}"` } func (job scheduledJob) changesGiven() bool { - return job.Command != nil || job.Size != nil || job.Schedule != nil + return job.Command != nil || job.Size != nil || job.Schedule != nil || job.TimeZone != nil || job.Retries != nil || job.Timeout != nil } type dockerfileBuild struct { @@ -487,11 +488,14 @@ func (job scheduledJob) applyUpdates(w format.Writer, cfg *apps.Config) { if job.Schedule != nil { cfg.ScheduledJobs[i].Schedule = *job.Schedule } + if job.TimeZone != nil { + cfg.ScheduledJobs[i].TimeZone = *job.TimeZone + } if job.Retries != nil { - cfg.DeployJob.Retries = job.Retries + cfg.ScheduledJobs[i].Retries = job.Retries } if job.Timeout != nil { - cfg.DeployJob.Timeout = &metav1.Duration{Duration: *job.Timeout} + cfg.ScheduledJobs[i].Timeout = &metav1.Duration{Duration: *job.Timeout} } return } @@ -504,6 +508,18 @@ func (job scheduledJob) applyUpdates(w format.Writer, cfg *apps.Config) { if job.Size != nil { newJob.Size = new(apps.ApplicationSize(*job.Size)) } + if job.TimeZone != nil { + newJob.TimeZone = *job.TimeZone + } + if job.Schedule != nil { + newJob.Schedule = *job.Schedule + } + if job.Retries != nil { + newJob.Retries = job.Retries + } + if job.Timeout != nil { + newJob.Timeout = &metav1.Duration{Duration: *job.Timeout} + } cfg.ScheduledJobs = append(cfg.ScheduledJobs, newJob) } diff --git a/update/application_test.go b/update/application_test.go index 82ce6320..84d61372 100644 --- a/update/application_test.go +++ b/update/application_test.go @@ -490,6 +490,67 @@ func TestApplication(t *testing.T) { is.Nil(updated.Spec.ForProvider.Config.DeployJob) }, }, + "add new scheduled job": { + orig: existingApp, + cmd: applicationCmd{ + ResourceCmd: ResourceCmd{ + Name: existingApp.Name, + }, + ScheduledJob: &scheduledJob{ + Name: new("nightly-backup"), + Command: new("./backup.sh"), + Schedule: new("0 3 * * *"), + TimeZone: new("Europe/Zurich"), + Retries: new(int32(2)), + Timeout: ptr.To(10 * time.Minute), + }, + }, + checkApp: func(t *testing.T, cmd applicationCmd, orig, updated *apps.Application) { + is := require.New(t) + is.Len(updated.Spec.ForProvider.Config.ScheduledJobs, 1) + job := updated.Spec.ForProvider.Config.ScheduledJobs[0] + is.Equal(*cmd.ScheduledJob.Name, job.Name) + is.Equal(*cmd.ScheduledJob.Command, job.Command) + is.Equal(*cmd.ScheduledJob.Schedule, job.Schedule) + is.Equal(*cmd.ScheduledJob.TimeZone, job.TimeZone) + is.Equal(*cmd.ScheduledJob.Retries, *job.Retries) + is.Equal(*cmd.ScheduledJob.Timeout, job.Timeout.Duration) + }, + }, + "update existing scheduled job": { + orig: func() *apps.Application { + a := existingApp.DeepCopy() + a.Spec.ForProvider.Config.ScheduledJobs = []apps.ScheduledJob{ + { + Job: apps.Job{Name: "nightly-backup", Command: "./backup.sh"}, + Schedule: "0 3 * * *", + FiniteJob: apps.FiniteJob{ + Retries: new(int32(1)), + Timeout: &metav1.Duration{Duration: 5 * time.Minute}, + }, + }, + } + return a + }(), + cmd: applicationCmd{ + ResourceCmd: ResourceCmd{ + Name: existingApp.Name, + }, + ScheduledJob: &scheduledJob{ + Name: new("nightly-backup"), + Retries: new(int32(5)), + Timeout: ptr.To(20 * time.Minute), + }, + }, + checkApp: func(t *testing.T, cmd applicationCmd, orig, updated *apps.Application) { + is := require.New(t) + is.Len(updated.Spec.ForProvider.Config.ScheduledJobs, 1) + job := updated.Spec.ForProvider.Config.ScheduledJobs[0] + is.Equal(*cmd.ScheduledJob.Retries, *job.Retries) + is.Equal(*cmd.ScheduledJob.Timeout, job.Timeout.Duration) + is.Equal(orig.Spec.ForProvider.Config.DeployJob, updated.Spec.ForProvider.Config.DeployJob) + }, + }, "retry release": { orig: existingApp, cmd: applicationCmd{