Skip to content

Commit 3294d7e

Browse files
authored
Merge pull request #2158 from rileykarson/cloud-functions-event-trigger
Add event_trigger to cloud functions
2 parents a6274e1 + e5d8575 commit 3294d7e

File tree

3 files changed

+360
-37
lines changed

3 files changed

+360
-37
lines changed

google/resource_cloudfunctions_function.go

+167-25
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,11 @@ func joinMapKeys(mapToJoin *map[int]bool) string {
7878

7979
func resourceCloudFunctionsFunction() *schema.Resource {
8080
return &schema.Resource{
81-
Create: resourceCloudFunctionsCreate,
82-
Read: resourceCloudFunctionsRead,
83-
Update: resourceCloudFunctionsUpdate,
84-
Delete: resourceCloudFunctionsDestroy,
81+
Create: resourceCloudFunctionsCreate,
82+
Read: resourceCloudFunctionsRead,
83+
Update: resourceCloudFunctionsUpdate,
84+
Delete: resourceCloudFunctionsDestroy,
85+
CustomizeDiff: resourceCloudFunctionsCustomizeDiff,
8586

8687
Importer: &schema.ResourceImporter{
8788
State: schema.ImportStatePassthrough,
@@ -177,7 +178,8 @@ func resourceCloudFunctionsFunction() *schema.Resource {
177178
"trigger_bucket": {
178179
Type: schema.TypeString,
179180
Optional: true,
180-
ForceNew: true,
181+
Computed: true,
182+
Deprecated: "This field is deprecated. Use `event_trigger` instead.",
181183
ConflictsWith: []string{"trigger_http", "trigger_topic"},
182184
},
183185

@@ -191,10 +193,46 @@ func resourceCloudFunctionsFunction() *schema.Resource {
191193
"trigger_topic": {
192194
Type: schema.TypeString,
193195
Optional: true,
194-
ForceNew: true,
196+
Computed: true,
197+
Deprecated: "This field is deprecated. Use `event_trigger` instead.",
195198
ConflictsWith: []string{"trigger_http", "trigger_bucket"},
196199
},
197200

201+
"event_trigger": {
202+
Type: schema.TypeList,
203+
Optional: true,
204+
Computed: true,
205+
ConflictsWith: []string{"trigger_http", "retry_on_failure", "trigger_topic", "trigger_http"},
206+
MaxItems: 1,
207+
Elem: &schema.Resource{
208+
Schema: map[string]*schema.Schema{
209+
"event_type": {
210+
Type: schema.TypeString,
211+
ForceNew: true,
212+
Required: true,
213+
},
214+
"resource": {
215+
Type: schema.TypeString,
216+
Required: true,
217+
},
218+
"failure_policy": {
219+
Type: schema.TypeList,
220+
Optional: true,
221+
Computed: true,
222+
MaxItems: 1,
223+
Elem: &schema.Resource{
224+
Schema: map[string]*schema.Schema{
225+
"retry": {
226+
Type: schema.TypeBool,
227+
// not strictly required, but this way an empty block can't be specified
228+
Required: true,
229+
},
230+
}},
231+
},
232+
},
233+
},
234+
},
235+
198236
"https_trigger_url": {
199237
Type: schema.TypeString,
200238
Optional: true,
@@ -204,6 +242,8 @@ func resourceCloudFunctionsFunction() *schema.Resource {
204242
"retry_on_failure": {
205243
Type: schema.TypeBool,
206244
Optional: true,
245+
Computed: true,
246+
Deprecated: "This field is deprecated. Use `event_trigger.failure_policy.retry` instead.",
207247
ConflictsWith: []string{"trigger_http"},
208248
},
209249

@@ -225,6 +265,28 @@ func resourceCloudFunctionsFunction() *schema.Resource {
225265
}
226266
}
227267

268+
func resourceCloudFunctionsCustomizeDiff(diff *schema.ResourceDiff, meta interface{}) error {
269+
if diff.HasChange("trigger_topic") {
270+
_, n := diff.GetChange("trigger_topic")
271+
if n == "" {
272+
diff.Clear("trigger_topic")
273+
} else {
274+
diff.ForceNew("trigger_topic")
275+
}
276+
}
277+
278+
if diff.HasChange("trigger_bucket") {
279+
_, n := diff.GetChange("trigger_bucket")
280+
if n == "" {
281+
diff.Clear("trigger_bucket")
282+
} else {
283+
diff.ForceNew("trigger_bucket")
284+
}
285+
}
286+
287+
return nil
288+
}
289+
228290
func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) error {
229291
config := meta.(*Config)
230292

@@ -253,7 +315,8 @@ func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) erro
253315
}
254316

255317
function := &cloudfunctions.CloudFunction{
256-
Name: cloudFuncId.cloudFunctionId(),
318+
Name: cloudFuncId.cloudFunctionId(),
319+
ForceSendFields: []string{},
257320
}
258321

259322
sourceArchiveBucket := d.Get("source_archive_bucket").(string)
@@ -277,13 +340,11 @@ func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) erro
277340
function.Timeout = fmt.Sprintf("%vs", v.(int))
278341
}
279342

280-
v, triggHttpOk := d.GetOk("trigger_http")
281-
if triggHttpOk && v.(bool) {
343+
if v, ok := d.GetOk("event_trigger"); ok {
344+
function.EventTrigger = expandEventTrigger(v.([]interface{}), project)
345+
} else if v, ok := d.GetOk("trigger_http"); ok && v.(bool) {
282346
function.HttpsTrigger = &cloudfunctions.HttpsTrigger{}
283-
}
284-
285-
v, triggTopicOk := d.GetOk("trigger_topic")
286-
if triggTopicOk {
347+
} else if v, ok := d.GetOk("trigger_topic"); ok {
287348
// Make PubSub event publish as in https://cloud.google.com/functions/docs/calling/pubsub
288349
function.EventTrigger = &cloudfunctions.EventTrigger{
289350
// Other events are not supported
@@ -297,10 +358,7 @@ func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) erro
297358
Retry: &cloudfunctions.Retry{},
298359
}
299360
}
300-
}
301-
302-
v, triggBucketOk := d.GetOk("trigger_bucket")
303-
if triggBucketOk {
361+
} else if v, ok := d.GetOk("trigger_bucket"); ok {
304362
// Make Storage event as in https://cloud.google.com/functions/docs/calling/storage
305363
function.EventTrigger = &cloudfunctions.EventTrigger{
306364
EventType: "providers/cloud.storage/eventTypes/object.change",
@@ -313,10 +371,8 @@ func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) erro
313371
Retry: &cloudfunctions.Retry{},
314372
}
315373
}
316-
}
317-
318-
if !triggHttpOk && !triggTopicOk && !triggBucketOk {
319-
return fmt.Errorf("One of arguments [trigger_topic, trigger_bucket, trigger_http] is required: " +
374+
} else {
375+
return fmt.Errorf("One of `event_trigger` or `trigger_http` is required: " +
320376
"You must specify a trigger when deploying a new function.")
321377
}
322378

@@ -389,16 +445,24 @@ func resourceCloudFunctionsRead(d *schema.ResourceData, meta interface{}) error
389445
d.Set("https_trigger_url", function.HttpsTrigger.Url)
390446
}
391447

448+
d.Set("event_trigger", flattenEventTrigger(function.EventTrigger))
392449
if function.EventTrigger != nil {
393450
switch function.EventTrigger.EventType {
394451
// From https://github.com/google/google-api-go-client/blob/master/cloudfunctions/v1/cloudfunctions-gen.go#L335
395452
case "google.pubsub.topic.publish":
396-
d.Set("trigger_topic", GetResourceNameFromSelfLink(function.EventTrigger.Resource))
453+
if _, ok := d.GetOk("trigger_topic"); ok {
454+
d.Set("trigger_topic", GetResourceNameFromSelfLink(function.EventTrigger.Resource))
455+
}
397456
case "providers/cloud.storage/eventTypes/object.change":
398-
d.Set("trigger_bucket", GetResourceNameFromSelfLink(function.EventTrigger.Resource))
457+
if _, ok := d.GetOk("trigger_bucket"); ok {
458+
d.Set("trigger_bucket", GetResourceNameFromSelfLink(function.EventTrigger.Resource))
459+
}
460+
}
461+
462+
if _, ok := d.GetOk("retry_on_failure"); ok {
463+
retry := function.EventTrigger.FailurePolicy != nil && function.EventTrigger.FailurePolicy.Retry != nil
464+
d.Set("retry_on_failure", retry)
399465
}
400-
retry := function.EventTrigger.FailurePolicy != nil && function.EventTrigger.FailurePolicy.Retry != nil
401-
d.Set("retry_on_failure", retry)
402466
}
403467
d.Set("region", cloudFuncId.Region)
404468
d.Set("project", cloudFuncId.Project)
@@ -410,6 +474,11 @@ func resourceCloudFunctionsUpdate(d *schema.ResourceData, meta interface{}) erro
410474
log.Printf("[DEBUG]: Updating google_cloudfunctions_function")
411475
config := meta.(*Config)
412476

477+
project, err := getProject(d, config)
478+
if err != nil {
479+
return err
480+
}
481+
413482
cloudFuncId, err := parseCloudFunctionId(d.Id(), config)
414483
if err != nil {
415484
return err
@@ -455,6 +524,7 @@ func resourceCloudFunctionsUpdate(d *schema.ResourceData, meta interface{}) erro
455524
updateMaskArr = append(updateMaskArr, "environment_variables")
456525
}
457526

527+
// Event trigger will run after failure policy and take precedence
458528
if d.HasChange("retry_on_failure") {
459529
if d.Get("retry_on_failure").(bool) {
460530
if function.EventTrigger == nil {
@@ -467,6 +537,11 @@ func resourceCloudFunctionsUpdate(d *schema.ResourceData, meta interface{}) erro
467537
updateMaskArr = append(updateMaskArr, "eventTrigger.failurePolicy.retry")
468538
}
469539

540+
if d.HasChange("event_trigger") {
541+
function.EventTrigger = expandEventTrigger(d.Get("event_trigger").([]interface{}), project)
542+
updateMaskArr = append(updateMaskArr, "eventTrigger", "eventTrigger.failurePolicy.retry")
543+
}
544+
470545
if len(updateMaskArr) > 0 {
471546
log.Printf("[DEBUG] Send Patch CloudFunction Configuration request: %#v", function)
472547
updateMask := strings.Join(updateMaskArr, ",")
@@ -509,3 +584,70 @@ func resourceCloudFunctionsDestroy(d *schema.ResourceData, meta interface{}) err
509584

510585
return nil
511586
}
587+
588+
func expandEventTrigger(configured []interface{}, project string) *cloudfunctions.EventTrigger {
589+
if len(configured) == 0 {
590+
return nil
591+
}
592+
593+
if data, ok := configured[0].(map[string]interface{}); ok {
594+
eventType := data["event_type"].(string)
595+
shape := ""
596+
switch {
597+
case strings.HasPrefix(eventType, "providers/cloud.storage/eventTypes/"):
598+
shape = "projects/%s/buckets/%s"
599+
case strings.HasPrefix(eventType, "providers/cloud.pubsub/eventTypes/"):
600+
shape = "projects/%s/topics/%s"
601+
}
602+
603+
return &cloudfunctions.EventTrigger{
604+
EventType: eventType,
605+
Resource: fmt.Sprintf(shape, project, data["resource"].(string)),
606+
FailurePolicy: expandFailurePolicy(data["failure_policy"].([]interface{})),
607+
}
608+
}
609+
610+
return nil
611+
}
612+
613+
func flattenEventTrigger(eventTrigger *cloudfunctions.EventTrigger) []map[string]interface{} {
614+
result := make([]map[string]interface{}, 0, 1)
615+
if eventTrigger == nil {
616+
return result
617+
}
618+
619+
result = append(result, map[string]interface{}{
620+
"event_type": eventTrigger.EventType,
621+
"resource": GetResourceNameFromSelfLink(eventTrigger.Resource),
622+
"failure_policy": flattenFailurePolicy(eventTrigger.FailurePolicy),
623+
})
624+
625+
return result
626+
}
627+
628+
func expandFailurePolicy(configured []interface{}) *cloudfunctions.FailurePolicy {
629+
if len(configured) == 0 {
630+
return &cloudfunctions.FailurePolicy{}
631+
}
632+
633+
if data, ok := configured[0].(map[string]interface{}); ok && data["retry"].(bool) {
634+
return &cloudfunctions.FailurePolicy{
635+
Retry: &cloudfunctions.Retry{},
636+
}
637+
}
638+
639+
return nil
640+
}
641+
642+
func flattenFailurePolicy(failurePolicy *cloudfunctions.FailurePolicy) []map[string]interface{} {
643+
result := make([]map[string]interface{}, 0, 1)
644+
if failurePolicy == nil {
645+
return nil
646+
}
647+
648+
result = append(result, map[string]interface{}{
649+
"retry": failurePolicy.Retry != nil,
650+
})
651+
652+
return result
653+
}

0 commit comments

Comments
 (0)