diff --git a/google/resource_cloudfunctions_function.go b/google/resource_cloudfunctions_function.go index 198df1e4839..b854e4f495b 100644 --- a/google/resource_cloudfunctions_function.go +++ b/google/resource_cloudfunctions_function.go @@ -90,6 +90,12 @@ func validateResourceCloudFunctionsFunctionName(v interface{}, k string) (ws []s return } +// based on compareSelfLinkOrResourceName, but less reusable and allows multi-/ +// strings in the new state (config) part +func compareSelfLinkOrResourceNameWithMultipleParts(_, old, new string, _ *schema.ResourceData) bool { + return strings.HasSuffix(old, new) +} + func resourceCloudFunctionsFunction() *schema.Resource { return &schema.Resource{ Create: resourceCloudFunctionsCreate, @@ -237,8 +243,9 @@ func resourceCloudFunctionsFunction() *schema.Resource { Required: true, }, "resource": { - Type: schema.TypeString, - Required: true, + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceNameWithMultipleParts, }, "failure_policy": { Type: schema.TypeList, @@ -562,26 +569,38 @@ func expandEventTrigger(configured []interface{}, project string) *cloudfunction data := configured[0].(map[string]interface{}) eventType := data["event_type"].(string) - shape := "" - switch { - case strings.HasPrefix(eventType, "google.storage.object."): - shape = "projects/%s/buckets/%s" - case strings.HasPrefix(eventType, "google.pubsub.topic."): - shape = "projects/%s/topics/%s" - // Legacy style triggers - case strings.HasPrefix(eventType, "providers/cloud.storage/eventTypes/"): - shape = "projects/%s/buckets/%s" - case strings.HasPrefix(eventType, "providers/cloud.pubsub/eventTypes/"): - shape = "projects/%s/topics/%s" - case strings.HasPrefix(eventType, "providers/cloud.firestore/eventTypes/"): - // Firestore doesn't not yet support multiple databases, so "(default)" is assumed. - // https://cloud.google.com/functions/docs/calling/cloud-firestore#deploying_your_function - shape = "projects/%s/databases/(default)/documents/%s" + resource := data["resource"].(string) + + // if resource starts with "projects/", we can reasonably assume it's a + // partial URI. Otherwise, it's a shortname. Construct a partial URI based + // on the event type if so. + if !strings.HasPrefix(resource, "projects/") { + shape := "" + switch { + case strings.HasPrefix(eventType, "google.storage.object."): + shape = "projects/%s/buckets/%s" + case strings.HasPrefix(eventType, "google.pubsub.topic."): + shape = "projects/%s/topics/%s" + // Legacy style triggers + case strings.HasPrefix(eventType, "providers/cloud.storage/eventTypes/"): + // Note that this is an uncommon way to refer to buckets; normally, + // you'd use to the global URL of the bucket and not the project + // scoped one. + shape = "projects/%s/buckets/%s" + case strings.HasPrefix(eventType, "providers/cloud.pubsub/eventTypes/"): + shape = "projects/%s/topics/%s" + case strings.HasPrefix(eventType, "providers/cloud.firestore/eventTypes/"): + // Firestore doesn't not yet support multiple databases, so "(default)" is assumed. + // https://cloud.google.com/functions/docs/calling/cloud-firestore#deploying_your_function + shape = "projects/%s/databases/(default)/documents/%s" + } + + resource = fmt.Sprintf(shape, project, resource) } return &cloudfunctions.EventTrigger{ EventType: eventType, - Resource: fmt.Sprintf(shape, project, data["resource"].(string)), + Resource: resource, FailurePolicy: expandFailurePolicy(data["failure_policy"].([]interface{})), } } @@ -592,28 +611,9 @@ func flattenEventTrigger(eventTrigger *cloudfunctions.EventTrigger) []map[string return result } - resource := "" - switch { - case strings.HasPrefix(eventTrigger.EventType, "google.storage.object."): - resource = GetResourceNameFromSelfLink(eventTrigger.Resource) - case strings.HasPrefix(eventTrigger.EventType, "google.pubsub.topic."): - resource = GetResourceNameFromSelfLink(eventTrigger.Resource) - // Legacy style triggers - case strings.HasPrefix(eventTrigger.EventType, "providers/cloud.storage/eventTypes/"): - resource = GetResourceNameFromSelfLink(eventTrigger.Resource) - case strings.HasPrefix(eventTrigger.EventType, "providers/cloud.pubsub/eventTypes/"): - resource = GetResourceNameFromSelfLink(eventTrigger.Resource) - case strings.HasPrefix(eventTrigger.EventType, "providers/cloud.firestore/eventTypes/"): - // Simply taking the substring after the last "/" is not sufficient for firestore as resources may have slashes. - // For the eventTrigger.Resource "projects/my-project/databases/(default)/documents/messages/{messageId}" we extract - // the resource "messages/{messageId}" by taking the everything after the 5th "/" - parts := strings.SplitN(eventTrigger.Resource, "/", 6) - resource = parts[len(parts)-1] - } - result = append(result, map[string]interface{}{ "event_type": eventTrigger.EventType, - "resource": resource, + "resource": eventTrigger.Resource, "failure_policy": flattenFailurePolicy(eventTrigger.FailurePolicy), }) diff --git a/google/resource_cloudfunctions_function_test.go b/google/resource_cloudfunctions_function_test.go index 75d9d24e162..e8b2ba3c739 100644 --- a/google/resource_cloudfunctions_function_test.go +++ b/google/resource_cloudfunctions_function_test.go @@ -579,6 +579,8 @@ resource "google_cloudfunctions_function" "function" { func testAccCloudFunctionsFunction_bucket(functionName string, bucketName string, zipFilePath string) string { return fmt.Sprintf(` +data "google_client_config" "current" {} + resource "google_storage_bucket" "bucket" { name = "%s" } @@ -599,7 +601,7 @@ resource "google_cloudfunctions_function" "function" { entry_point = "helloGCS" event_trigger { event_type = "google.storage.object.finalize" - resource = "${google_storage_bucket.bucket.name}" + resource = "projects/${data.google_client_config.current.project}/buckets/${google_storage_bucket.bucket.name}" failure_policy { retry = true } diff --git a/website/docs/r/cloudfunctions_function.html.markdown b/website/docs/r/cloudfunctions_function.html.markdown index c7ce5aa73b2..96d25b75f39 100644 --- a/website/docs/r/cloudfunctions_function.html.markdown +++ b/website/docs/r/cloudfunctions_function.html.markdown @@ -95,7 +95,8 @@ Cloud Storage, Cloud Pub/Sub and Cloud Firestore triggers are supported at this Legacy triggers are supported, such as `"providers/cloud.storage/eventTypes/object.change"`, `"providers/cloud.pubsub/eventTypes/topic.publish"` and `"providers/cloud.firestore/eventTypes/document.create"`. -* `resource` - (Required) Required. The name of the resource from which to observe events, for example, `"myBucket"` +* `resource` - (Required) Required. The name or partial URI of the resource from +which to observe events. For example, `"myBucket"` or `"projects/my-project/topics/my-topic"` * `failure_policy` - (Optional) Specifies policy for failed executions. Structure is documented below.