Skip to content

Commit 9e91f2d

Browse files
Support cloud scheduler update (#4409) (#2882)
* Specify which apis are required for cloud scheduler * Add support update api for cloud scheduler Signed-off-by: Modular Magician <[email protected]>
1 parent e1941cc commit 9e91f2d

File tree

3 files changed

+94
-34
lines changed

3 files changed

+94
-34
lines changed

.changelog/4409.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
cloudscheduler: Fixed unnecessary recreate for `google_cloud_scheduler_job`
3+
```

google-beta/resource_cloud_scheduler_job.go

Lines changed: 90 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ func resourceCloudSchedulerJob() *schema.Resource {
9999
return &schema.Resource{
100100
Create: resourceCloudSchedulerJobCreate,
101101
Read: resourceCloudSchedulerJobRead,
102+
Update: resourceCloudSchedulerJobUpdate,
102103
Delete: resourceCloudSchedulerJobDelete,
103104

104105
Importer: &schema.ResourceImporter{
@@ -107,6 +108,7 @@ func resourceCloudSchedulerJob() *schema.Resource {
107108

108109
Timeouts: &schema.ResourceTimeout{
109110
Create: schema.DefaultTimeout(4 * time.Minute),
111+
Update: schema.DefaultTimeout(4 * time.Minute),
110112
Delete: schema.DefaultTimeout(4 * time.Minute),
111113
},
112114

@@ -122,7 +124,6 @@ func resourceCloudSchedulerJob() *schema.Resource {
122124
"app_engine_http_target": {
123125
Type: schema.TypeList,
124126
Optional: true,
125-
ForceNew: true,
126127
Description: `App Engine HTTP target.
127128
If the job providers a App Engine HTTP target the cron will
128129
send a request to the service instance`,
@@ -132,7 +133,6 @@ send a request to the service instance`,
132133
"relative_uri": {
133134
Type: schema.TypeString,
134135
Required: true,
135-
ForceNew: true,
136136
Description: `The relative URI.
137137
The relative URL must begin with "/" and must be a valid HTTP relative URL.
138138
It can contain a path, query string arguments, and \# fragments.
@@ -142,31 +142,27 @@ No spaces are allowed, and the maximum length allowed is 2083 characters`,
142142
"app_engine_routing": {
143143
Type: schema.TypeList,
144144
Optional: true,
145-
ForceNew: true,
146145
Description: `App Engine Routing setting for the job.`,
147146
MaxItems: 1,
148147
Elem: &schema.Resource{
149148
Schema: map[string]*schema.Schema{
150149
"instance": {
151150
Type: schema.TypeString,
152151
Optional: true,
153-
ForceNew: true,
154152
Description: `App instance.
155153
By default, the job is sent to an instance which is available when the job is attempted.`,
156154
AtLeastOneOf: []string{"app_engine_http_target.0.app_engine_routing.0.service", "app_engine_http_target.0.app_engine_routing.0.version", "app_engine_http_target.0.app_engine_routing.0.instance"},
157155
},
158156
"service": {
159157
Type: schema.TypeString,
160158
Optional: true,
161-
ForceNew: true,
162159
Description: `App service.
163160
By default, the job is sent to the service which is the default service when the job is attempted.`,
164161
AtLeastOneOf: []string{"app_engine_http_target.0.app_engine_routing.0.service", "app_engine_http_target.0.app_engine_routing.0.version", "app_engine_http_target.0.app_engine_routing.0.instance"},
165162
},
166163
"version": {
167164
Type: schema.TypeString,
168165
Optional: true,
169-
ForceNew: true,
170166
Description: `App version.
171167
By default, the job is sent to the version which is the default version when the job is attempted.`,
172168
AtLeastOneOf: []string{"app_engine_http_target.0.app_engine_routing.0.service", "app_engine_http_target.0.app_engine_routing.0.version", "app_engine_http_target.0.app_engine_routing.0.instance"},
@@ -177,7 +173,6 @@ By default, the job is sent to the version which is the default version when the
177173
"body": {
178174
Type: schema.TypeString,
179175
Optional: true,
180-
ForceNew: true,
181176
Description: `HTTP request body.
182177
A request body is allowed only if the HTTP method is POST or PUT.
183178
It will result in invalid argument error to set a body on a job with an incompatible HttpMethod.
@@ -187,7 +182,6 @@ A base64-encoded string.`,
187182
"headers": {
188183
Type: schema.TypeMap,
189184
Optional: true,
190-
ForceNew: true,
191185
ValidateFunc: validateHttpHeaders(),
192186
Description: `HTTP request headers.
193187
This map contains the header field names and values.
@@ -197,7 +191,6 @@ Headers can be set when the job is created.`,
197191
"http_method": {
198192
Type: schema.TypeString,
199193
Optional: true,
200-
ForceNew: true,
201194
Description: `Which HTTP method to use for the request.`,
202195
},
203196
},
@@ -207,7 +200,6 @@ Headers can be set when the job is created.`,
207200
"attempt_deadline": {
208201
Type: schema.TypeString,
209202
Optional: true,
210-
ForceNew: true,
211203
DiffSuppressFunc: emptyOrDefaultStringSuppress("180s"),
212204
Description: `The deadline for job attempts. If the request handler does not respond by this deadline then the request is
213205
cancelled and the attempt is marked as a DEADLINE_EXCEEDED failure. The failed attempt can be viewed in
@@ -222,14 +214,12 @@ A duration in seconds with up to nine fractional digits, terminated by 's'. Exam
222214
"description": {
223215
Type: schema.TypeString,
224216
Optional: true,
225-
ForceNew: true,
226217
Description: `A human-readable description for the job.
227218
This string must not contain more than 500 characters.`,
228219
},
229220
"http_target": {
230221
Type: schema.TypeList,
231222
Optional: true,
232-
ForceNew: true,
233223
Description: `HTTP target.
234224
If the job providers a http_target the cron will
235225
send a request to the targeted url`,
@@ -239,13 +229,11 @@ send a request to the targeted url`,
239229
"uri": {
240230
Type: schema.TypeString,
241231
Required: true,
242-
ForceNew: true,
243232
Description: `The full URI path that the request will be sent to.`,
244233
},
245234
"body": {
246235
Type: schema.TypeString,
247236
Optional: true,
248-
ForceNew: true,
249237
Description: `HTTP request body.
250238
A request body is allowed only if the HTTP method is POST, PUT, or PATCH.
251239
It is an error to set body on a job with an incompatible HttpMethod.
@@ -255,7 +243,6 @@ A base64-encoded string.`,
255243
"headers": {
256244
Type: schema.TypeMap,
257245
Optional: true,
258-
ForceNew: true,
259246
ValidateFunc: validateHttpHeaders(),
260247
Description: `This map contains the header field names and values.
261248
Repeated headers are not supported, but a header value can contain commas.`,
@@ -264,13 +251,11 @@ Repeated headers are not supported, but a header value can contain commas.`,
264251
"http_method": {
265252
Type: schema.TypeString,
266253
Optional: true,
267-
ForceNew: true,
268254
Description: `Which HTTP method to use for the request.`,
269255
},
270256
"oauth_token": {
271257
Type: schema.TypeList,
272258
Optional: true,
273-
ForceNew: true,
274259
DiffSuppressFunc: authHeaderDiffSuppress,
275260
Description: `Contains information needed for generating an OAuth token.
276261
This type of authorization should be used when sending requests to a GCP endpoint.`,
@@ -280,14 +265,12 @@ This type of authorization should be used when sending requests to a GCP endpoin
280265
"service_account_email": {
281266
Type: schema.TypeString,
282267
Required: true,
283-
ForceNew: true,
284268
Description: `Service account email to be used for generating OAuth token.
285269
The service account must be within the same project as the job.`,
286270
},
287271
"scope": {
288272
Type: schema.TypeString,
289273
Optional: true,
290-
ForceNew: true,
291274
Description: `OAuth scope to be used for generating OAuth access token. If not specified,
292275
"https://www.googleapis.com/auth/cloud-platform" will be used.`,
293276
},
@@ -297,7 +280,6 @@ The service account must be within the same project as the job.`,
297280
"oidc_token": {
298281
Type: schema.TypeList,
299282
Optional: true,
300-
ForceNew: true,
301283
DiffSuppressFunc: authHeaderDiffSuppress,
302284
Description: `Contains information needed for generating an OpenID Connect token.
303285
This type of authorization should be used when sending requests to third party endpoints or Cloud Run.`,
@@ -307,14 +289,12 @@ This type of authorization should be used when sending requests to third party e
307289
"service_account_email": {
308290
Type: schema.TypeString,
309291
Required: true,
310-
ForceNew: true,
311292
Description: `Service account email to be used for generating OAuth token.
312293
The service account must be within the same project as the job.`,
313294
},
314295
"audience": {
315296
Type: schema.TypeString,
316297
Optional: true,
317-
ForceNew: true,
318298
Description: `Audience to be used when generating OIDC token. If not specified,
319299
the URI specified in target will be used.`,
320300
},
@@ -328,7 +308,6 @@ the URI specified in target will be used.`,
328308
"pubsub_target": {
329309
Type: schema.TypeList,
330310
Optional: true,
331-
ForceNew: true,
332311
Description: `Pub/Sub target
333312
If the job providers a Pub/Sub target the cron will publish
334313
a message to the provided topic`,
@@ -338,7 +317,6 @@ a message to the provided topic`,
338317
"topic_name": {
339318
Type: schema.TypeString,
340319
Required: true,
341-
ForceNew: true,
342320
Description: `The full resource name for the Cloud Pub/Sub topic to which
343321
messages will be published when a job is delivered. ~>**NOTE:**
344322
The topic name must be in the same format as required by PubSub's
@@ -347,15 +325,13 @@ PublishRequest.name, e.g. 'projects/my-project/topics/my-topic'.`,
347325
"attributes": {
348326
Type: schema.TypeMap,
349327
Optional: true,
350-
ForceNew: true,
351328
Description: `Attributes for PubsubMessage.
352329
Pubsub message must contain either non-empty data, or at least one attribute.`,
353330
Elem: &schema.Schema{Type: schema.TypeString},
354331
},
355332
"data": {
356333
Type: schema.TypeString,
357334
Optional: true,
358-
ForceNew: true,
359335
Description: `The message payload for PubsubMessage.
360336
Pubsub message must contain either non-empty data, or at least one attribute.`,
361337
},
@@ -373,7 +349,6 @@ Pubsub message must contain either non-empty data, or at least one attribute.`,
373349
"retry_config": {
374350
Type: schema.TypeList,
375351
Optional: true,
376-
ForceNew: true,
377352
Description: `By default, if a job does not complete successfully,
378353
meaning that an acknowledgement is not received from the handler,
379354
then it will be retried with exponential backoff according to the settings`,
@@ -384,7 +359,6 @@ then it will be retried with exponential backoff according to the settings`,
384359
Type: schema.TypeString,
385360
Computed: true,
386361
Optional: true,
387-
ForceNew: true,
388362
Description: `The maximum amount of time to wait before retrying a job after it fails.
389363
A duration in seconds with up to nine fractional digits, terminated by 's'.`,
390364
AtLeastOneOf: []string{"retry_config.0.retry_count", "retry_config.0.max_retry_duration", "retry_config.0.min_backoff_duration", "retry_config.0.max_backoff_duration", "retry_config.0.max_doublings"},
@@ -393,7 +367,6 @@ A duration in seconds with up to nine fractional digits, terminated by 's'.`,
393367
Type: schema.TypeInt,
394368
Computed: true,
395369
Optional: true,
396-
ForceNew: true,
397370
Description: `The time between retries will double maxDoublings times.
398371
A job's retry interval starts at minBackoffDuration,
399372
then doubles maxDoublings times, then increases linearly,
@@ -404,7 +377,6 @@ and finally retries retries at intervals of maxBackoffDuration up to retryCount
404377
Type: schema.TypeString,
405378
Computed: true,
406379
Optional: true,
407-
ForceNew: true,
408380
Description: `The time limit for retrying a failed job, measured from time when an execution was first attempted.
409381
If specified with retryCount, the job will be retried until both limits are reached.
410382
A duration in seconds with up to nine fractional digits, terminated by 's'.`,
@@ -414,7 +386,6 @@ A duration in seconds with up to nine fractional digits, terminated by 's'.`,
414386
Type: schema.TypeString,
415387
Computed: true,
416388
Optional: true,
417-
ForceNew: true,
418389
Description: `The minimum amount of time to wait before retrying a job after it fails.
419390
A duration in seconds with up to nine fractional digits, terminated by 's'.`,
420391
AtLeastOneOf: []string{"retry_config.0.retry_count", "retry_config.0.max_retry_duration", "retry_config.0.min_backoff_duration", "retry_config.0.max_backoff_duration", "retry_config.0.max_doublings"},
@@ -423,7 +394,6 @@ A duration in seconds with up to nine fractional digits, terminated by 's'.`,
423394
Type: schema.TypeInt,
424395
Computed: true,
425396
Optional: true,
426-
ForceNew: true,
427397
Description: `The number of attempts that the system will make to run a
428398
job using the exponential backoff procedure described by maxDoublings.
429399
Values greater than 5 and negative values are not allowed.`,
@@ -435,13 +405,11 @@ Values greater than 5 and negative values are not allowed.`,
435405
"schedule": {
436406
Type: schema.TypeString,
437407
Optional: true,
438-
ForceNew: true,
439408
Description: `Describes the schedule on which the job will be executed.`,
440409
},
441410
"time_zone": {
442411
Type: schema.TypeString,
443412
Optional: true,
444-
ForceNew: true,
445413
Description: `Specifies the time zone to be used in interpreting schedule.
446414
The value of this field must be a time zone name from the tz database.`,
447415
Default: "Etc/UTC",
@@ -629,6 +597,94 @@ func resourceCloudSchedulerJobRead(d *schema.ResourceData, meta interface{}) err
629597
return nil
630598
}
631599

600+
func resourceCloudSchedulerJobUpdate(d *schema.ResourceData, meta interface{}) error {
601+
config := meta.(*Config)
602+
userAgent, err := generateUserAgentString(d, config.userAgent)
603+
if err != nil {
604+
return err
605+
}
606+
607+
billingProject := ""
608+
609+
project, err := getProject(d, config)
610+
if err != nil {
611+
return fmt.Errorf("Error fetching project for Job: %s", err)
612+
}
613+
billingProject = project
614+
615+
obj := make(map[string]interface{})
616+
descriptionProp, err := expandCloudSchedulerJobDescription(d.Get("description"), d, config)
617+
if err != nil {
618+
return err
619+
} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
620+
obj["description"] = descriptionProp
621+
}
622+
scheduleProp, err := expandCloudSchedulerJobSchedule(d.Get("schedule"), d, config)
623+
if err != nil {
624+
return err
625+
} else if v, ok := d.GetOkExists("schedule"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, scheduleProp)) {
626+
obj["schedule"] = scheduleProp
627+
}
628+
timeZoneProp, err := expandCloudSchedulerJobTimeZone(d.Get("time_zone"), d, config)
629+
if err != nil {
630+
return err
631+
} else if v, ok := d.GetOkExists("time_zone"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, timeZoneProp)) {
632+
obj["timeZone"] = timeZoneProp
633+
}
634+
attemptDeadlineProp, err := expandCloudSchedulerJobAttemptDeadline(d.Get("attempt_deadline"), d, config)
635+
if err != nil {
636+
return err
637+
} else if v, ok := d.GetOkExists("attempt_deadline"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, attemptDeadlineProp)) {
638+
obj["attemptDeadline"] = attemptDeadlineProp
639+
}
640+
retryConfigProp, err := expandCloudSchedulerJobRetryConfig(d.Get("retry_config"), d, config)
641+
if err != nil {
642+
return err
643+
} else if v, ok := d.GetOkExists("retry_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, retryConfigProp)) {
644+
obj["retryConfig"] = retryConfigProp
645+
}
646+
pubsubTargetProp, err := expandCloudSchedulerJobPubsubTarget(d.Get("pubsub_target"), d, config)
647+
if err != nil {
648+
return err
649+
} else if v, ok := d.GetOkExists("pubsub_target"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, pubsubTargetProp)) {
650+
obj["pubsubTarget"] = pubsubTargetProp
651+
}
652+
appEngineHttpTargetProp, err := expandCloudSchedulerJobAppEngineHttpTarget(d.Get("app_engine_http_target"), d, config)
653+
if err != nil {
654+
return err
655+
} else if v, ok := d.GetOkExists("app_engine_http_target"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, appEngineHttpTargetProp)) {
656+
obj["appEngineHttpTarget"] = appEngineHttpTargetProp
657+
}
658+
httpTargetProp, err := expandCloudSchedulerJobHttpTarget(d.Get("http_target"), d, config)
659+
if err != nil {
660+
return err
661+
} else if v, ok := d.GetOkExists("http_target"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, httpTargetProp)) {
662+
obj["httpTarget"] = httpTargetProp
663+
}
664+
665+
url, err := replaceVars(d, config, "{{CloudSchedulerBasePath}}projects/{{project}}/locations/{{region}}/jobs/{{name}}")
666+
if err != nil {
667+
return err
668+
}
669+
670+
log.Printf("[DEBUG] Updating Job %q: %#v", d.Id(), obj)
671+
672+
// err == nil indicates that the billing_project value was found
673+
if bp, err := getBillingProject(d, config); err == nil {
674+
billingProject = bp
675+
}
676+
677+
res, err := sendRequestWithTimeout(config, "PATCH", billingProject, url, userAgent, obj, d.Timeout(schema.TimeoutUpdate))
678+
679+
if err != nil {
680+
return fmt.Errorf("Error updating Job %q: %s", d.Id(), err)
681+
} else {
682+
log.Printf("[DEBUG] Finished updating Job %q: %#v", d.Id(), res)
683+
}
684+
685+
return resourceCloudSchedulerJobRead(d, meta)
686+
}
687+
632688
func resourceCloudSchedulerJobDelete(d *schema.ResourceData, meta interface{}) error {
633689
config := meta.(*Config)
634690
userAgent, err := generateUserAgentString(d, config.userAgent)

website/docs/r/cloud_scheduler_job.html.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ This resource provides the following
430430
[Timeouts](/docs/configuration/resources.html#timeouts) configuration options:
431431

432432
- `create` - Default is 4 minutes.
433+
- `update` - Default is 4 minutes.
433434
- `delete` - Default is 4 minutes.
434435

435436
## Import

0 commit comments

Comments
 (0)