diff --git a/.changelog/4023.txt b/.changelog/4023.txt new file mode 100644 index 0000000000..94573165ee --- /dev/null +++ b/.changelog/4023.txt @@ -0,0 +1,5 @@ +```release-note:enhancement +cloud_asset: Added `condition` to `google_cloud_asset_organization_feed` +cloud_asset: Added `condition` to `google_cloud_asset_folder_feed` +cloud_asset: Added `condition` to `google_cloud_asset_project_feed` +``` diff --git a/google-beta/resource_cloud_asset_folder_feed.go b/google-beta/resource_cloud_asset_folder_feed.go index aa7881c017..db3762bb63 100644 --- a/google-beta/resource_cloud_asset_folder_feed.go +++ b/google-beta/resource_cloud_asset_folder_feed.go @@ -112,6 +112,43 @@ supported asset types.`, Type: schema.TypeString, }, }, + "condition": { + Type: schema.TypeList, + Optional: true, + Description: `A condition which determines whether an asset update should be published. If specified, an asset +will be returned only when the expression evaluates to true. When set, expression field +must be a valid CEL expression on a TemporalAsset with name temporal_asset. Example: a Feed with +expression "temporal_asset.deleted == true" will only publish Asset deletions. Other fields of +condition are optional.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Required: true, + Description: `Textual representation of an expression in Common Expression Language syntax.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `Description of the expression. This is a longer text which describes the expression, +e.g. when hovered over it in a UI.`, + }, + "location": { + Type: schema.TypeString, + Optional: true, + Description: `String indicating the location of the expression for error reporting, e.g. a file +name and a position in the file.`, + }, + "title": { + Type: schema.TypeString, + Optional: true, + Description: `Title for the expression, i.e. a short string describing its purpose. +This can be used e.g. in UIs which allow to enter the expression.`, + }, + }, + }, + }, "content_type": { Type: schema.TypeString, Optional: true, @@ -165,6 +202,12 @@ func resourceCloudAssetFolderFeedCreate(d *schema.ResourceData, meta interface{} } else if v, ok := d.GetOkExists("feed_output_config"); !isEmptyValue(reflect.ValueOf(feedOutputConfigProp)) && (ok || !reflect.DeepEqual(v, feedOutputConfigProp)) { obj["feedOutputConfig"] = feedOutputConfigProp } + conditionProp, err := expandCloudAssetFolderFeedCondition(d.Get("condition"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("condition"); !isEmptyValue(reflect.ValueOf(conditionProp)) && (ok || !reflect.DeepEqual(v, conditionProp)) { + obj["condition"] = conditionProp + } obj, err = resourceCloudAssetFolderFeedEncoder(d, meta, obj) if err != nil { @@ -260,6 +303,9 @@ func resourceCloudAssetFolderFeedRead(d *schema.ResourceData, meta interface{}) if err := d.Set("feed_output_config", flattenCloudAssetFolderFeedFeedOutputConfig(res["feedOutputConfig"], d, config)); err != nil { return fmt.Errorf("Error reading FolderFeed: %s", err) } + if err := d.Set("condition", flattenCloudAssetFolderFeedCondition(res["condition"], d, config)); err != nil { + return fmt.Errorf("Error reading FolderFeed: %s", err) + } return nil } @@ -298,6 +344,12 @@ func resourceCloudAssetFolderFeedUpdate(d *schema.ResourceData, meta interface{} } else if v, ok := d.GetOkExists("feed_output_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, feedOutputConfigProp)) { obj["feedOutputConfig"] = feedOutputConfigProp } + conditionProp, err := expandCloudAssetFolderFeedCondition(d.Get("condition"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("condition"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, conditionProp)) { + obj["condition"] = conditionProp + } obj, err = resourceCloudAssetFolderFeedEncoder(d, meta, obj) if err != nil { @@ -327,6 +379,10 @@ func resourceCloudAssetFolderFeedUpdate(d *schema.ResourceData, meta interface{} if d.HasChange("feed_output_config") { updateMask = append(updateMask, "feedOutputConfig") } + + if d.HasChange("condition") { + updateMask = append(updateMask, "condition") + } // updateMask is a URL parameter but not present in the schema, so replaceVars // won't set it url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) @@ -446,6 +502,41 @@ func flattenCloudAssetFolderFeedFeedOutputConfigPubsubDestinationTopic(v interfa return v } +func flattenCloudAssetFolderFeedCondition(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["expression"] = + flattenCloudAssetFolderFeedConditionExpression(original["expression"], d, config) + transformed["title"] = + flattenCloudAssetFolderFeedConditionTitle(original["title"], d, config) + transformed["description"] = + flattenCloudAssetFolderFeedConditionDescription(original["description"], d, config) + transformed["location"] = + flattenCloudAssetFolderFeedConditionLocation(original["location"], d, config) + return []interface{}{transformed} +} +func flattenCloudAssetFolderFeedConditionExpression(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetFolderFeedConditionTitle(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetFolderFeedConditionDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetFolderFeedConditionLocation(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func expandCloudAssetFolderFeedAssetNames(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -500,6 +591,62 @@ func expandCloudAssetFolderFeedFeedOutputConfigPubsubDestinationTopic(v interfac return v, nil } +func expandCloudAssetFolderFeedCondition(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedExpression, err := expandCloudAssetFolderFeedConditionExpression(original["expression"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedExpression); val.IsValid() && !isEmptyValue(val) { + transformed["expression"] = transformedExpression + } + + transformedTitle, err := expandCloudAssetFolderFeedConditionTitle(original["title"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTitle); val.IsValid() && !isEmptyValue(val) { + transformed["title"] = transformedTitle + } + + transformedDescription, err := expandCloudAssetFolderFeedConditionDescription(original["description"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) { + transformed["description"] = transformedDescription + } + + transformedLocation, err := expandCloudAssetFolderFeedConditionLocation(original["location"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLocation); val.IsValid() && !isEmptyValue(val) { + transformed["location"] = transformedLocation + } + + return transformed, nil +} + +func expandCloudAssetFolderFeedConditionExpression(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetFolderFeedConditionTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetFolderFeedConditionDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetFolderFeedConditionLocation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func resourceCloudAssetFolderFeedEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { // Remove the "folders/" prefix from the folder ID if folder, ok := d.GetOkExists("folder"); ok { diff --git a/google-beta/resource_cloud_asset_folder_feed_generated_test.go b/google-beta/resource_cloud_asset_folder_feed_generated_test.go index ab224f9824..64d49db09b 100644 --- a/google-beta/resource_cloud_asset_folder_feed_generated_test.go +++ b/google-beta/resource_cloud_asset_folder_feed_generated_test.go @@ -74,6 +74,15 @@ resource "google_cloud_asset_folder_feed" "folder_feed" { } } + condition { + expression = <<-EOT + !temporal_asset.deleted && + temporal_asset.prior_asset_state == google.cloud.asset.v1.TemporalAsset.PriorAssetState.DOES_NOT_EXIST + EOT + title = "created" + description = "Send notifications on creation events" + } + # Wait for the permission to be ready on the destination topic. depends_on = [ google_pubsub_topic_iam_member.cloud_asset_writer, diff --git a/google-beta/resource_cloud_asset_organization_feed.go b/google-beta/resource_cloud_asset_organization_feed.go index cccabca287..5be5aae676 100644 --- a/google-beta/resource_cloud_asset_organization_feed.go +++ b/google-beta/resource_cloud_asset_organization_feed.go @@ -112,6 +112,43 @@ supported asset types.`, Type: schema.TypeString, }, }, + "condition": { + Type: schema.TypeList, + Optional: true, + Description: `A condition which determines whether an asset update should be published. If specified, an asset +will be returned only when the expression evaluates to true. When set, expression field +must be a valid CEL expression on a TemporalAsset with name temporal_asset. Example: a Feed with +expression "temporal_asset.deleted == true" will only publish Asset deletions. Other fields of +condition are optional.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Required: true, + Description: `Textual representation of an expression in Common Expression Language syntax.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `Description of the expression. This is a longer text which describes the expression, +e.g. when hovered over it in a UI.`, + }, + "location": { + Type: schema.TypeString, + Optional: true, + Description: `String indicating the location of the expression for error reporting, e.g. a file +name and a position in the file.`, + }, + "title": { + Type: schema.TypeString, + Optional: true, + Description: `Title for the expression, i.e. a short string describing its purpose. +This can be used e.g. in UIs which allow to enter the expression.`, + }, + }, + }, + }, "content_type": { Type: schema.TypeString, Optional: true, @@ -159,6 +196,12 @@ func resourceCloudAssetOrganizationFeedCreate(d *schema.ResourceData, meta inter } else if v, ok := d.GetOkExists("feed_output_config"); !isEmptyValue(reflect.ValueOf(feedOutputConfigProp)) && (ok || !reflect.DeepEqual(v, feedOutputConfigProp)) { obj["feedOutputConfig"] = feedOutputConfigProp } + conditionProp, err := expandCloudAssetOrganizationFeedCondition(d.Get("condition"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("condition"); !isEmptyValue(reflect.ValueOf(conditionProp)) && (ok || !reflect.DeepEqual(v, conditionProp)) { + obj["condition"] = conditionProp + } obj, err = resourceCloudAssetOrganizationFeedEncoder(d, meta, obj) if err != nil { @@ -251,6 +294,9 @@ func resourceCloudAssetOrganizationFeedRead(d *schema.ResourceData, meta interfa if err := d.Set("feed_output_config", flattenCloudAssetOrganizationFeedFeedOutputConfig(res["feedOutputConfig"], d, config)); err != nil { return fmt.Errorf("Error reading OrganizationFeed: %s", err) } + if err := d.Set("condition", flattenCloudAssetOrganizationFeedCondition(res["condition"], d, config)); err != nil { + return fmt.Errorf("Error reading OrganizationFeed: %s", err) + } return nil } @@ -289,6 +335,12 @@ func resourceCloudAssetOrganizationFeedUpdate(d *schema.ResourceData, meta inter } else if v, ok := d.GetOkExists("feed_output_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, feedOutputConfigProp)) { obj["feedOutputConfig"] = feedOutputConfigProp } + conditionProp, err := expandCloudAssetOrganizationFeedCondition(d.Get("condition"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("condition"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, conditionProp)) { + obj["condition"] = conditionProp + } obj, err = resourceCloudAssetOrganizationFeedEncoder(d, meta, obj) if err != nil { @@ -318,6 +370,10 @@ func resourceCloudAssetOrganizationFeedUpdate(d *schema.ResourceData, meta inter if d.HasChange("feed_output_config") { updateMask = append(updateMask, "feedOutputConfig") } + + if d.HasChange("condition") { + updateMask = append(updateMask, "condition") + } // updateMask is a URL parameter but not present in the schema, so replaceVars // won't set it url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) @@ -433,6 +489,41 @@ func flattenCloudAssetOrganizationFeedFeedOutputConfigPubsubDestinationTopic(v i return v } +func flattenCloudAssetOrganizationFeedCondition(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["expression"] = + flattenCloudAssetOrganizationFeedConditionExpression(original["expression"], d, config) + transformed["title"] = + flattenCloudAssetOrganizationFeedConditionTitle(original["title"], d, config) + transformed["description"] = + flattenCloudAssetOrganizationFeedConditionDescription(original["description"], d, config) + transformed["location"] = + flattenCloudAssetOrganizationFeedConditionLocation(original["location"], d, config) + return []interface{}{transformed} +} +func flattenCloudAssetOrganizationFeedConditionExpression(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetOrganizationFeedConditionTitle(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetOrganizationFeedConditionDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetOrganizationFeedConditionLocation(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func expandCloudAssetOrganizationFeedAssetNames(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -487,6 +578,62 @@ func expandCloudAssetOrganizationFeedFeedOutputConfigPubsubDestinationTopic(v in return v, nil } +func expandCloudAssetOrganizationFeedCondition(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedExpression, err := expandCloudAssetOrganizationFeedConditionExpression(original["expression"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedExpression); val.IsValid() && !isEmptyValue(val) { + transformed["expression"] = transformedExpression + } + + transformedTitle, err := expandCloudAssetOrganizationFeedConditionTitle(original["title"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTitle); val.IsValid() && !isEmptyValue(val) { + transformed["title"] = transformedTitle + } + + transformedDescription, err := expandCloudAssetOrganizationFeedConditionDescription(original["description"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) { + transformed["description"] = transformedDescription + } + + transformedLocation, err := expandCloudAssetOrganizationFeedConditionLocation(original["location"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLocation); val.IsValid() && !isEmptyValue(val) { + transformed["location"] = transformedLocation + } + + return transformed, nil +} + +func expandCloudAssetOrganizationFeedConditionExpression(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetOrganizationFeedConditionTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetOrganizationFeedConditionDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetOrganizationFeedConditionLocation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func resourceCloudAssetOrganizationFeedEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { // Remove the "folders/" prefix from the folder ID if folder, ok := d.GetOkExists("folder"); ok { diff --git a/google-beta/resource_cloud_asset_organization_feed_generated_test.go b/google-beta/resource_cloud_asset_organization_feed_generated_test.go index 0293cd6f2b..7d82a2e517 100644 --- a/google-beta/resource_cloud_asset_organization_feed_generated_test.go +++ b/google-beta/resource_cloud_asset_organization_feed_generated_test.go @@ -74,6 +74,15 @@ resource "google_cloud_asset_organization_feed" "organization_feed" { } } + condition { + expression = <<-EOT + !temporal_asset.deleted && + temporal_asset.prior_asset_state == google.cloud.asset.v1.TemporalAsset.PriorAssetState.DOES_NOT_EXIST + EOT + title = "created" + description = "Send notifications on creation events" + } + # Wait for the permission to be ready on the destination topic. depends_on = [ google_pubsub_topic_iam_member.cloud_asset_writer, diff --git a/google-beta/resource_cloud_asset_project_feed.go b/google-beta/resource_cloud_asset_project_feed.go index 3ad33698f1..a800d6c093 100644 --- a/google-beta/resource_cloud_asset_project_feed.go +++ b/google-beta/resource_cloud_asset_project_feed.go @@ -106,6 +106,43 @@ destination pubsub topic. It also specifies the project for API enablement check, quota, and billing. If not specified, the resource's project will be used.`, }, + "condition": { + Type: schema.TypeList, + Optional: true, + Description: `A condition which determines whether an asset update should be published. If specified, an asset +will be returned only when the expression evaluates to true. When set, expression field +must be a valid CEL expression on a TemporalAsset with name temporal_asset. Example: a Feed with +expression "temporal_asset.deleted == true" will only publish Asset deletions. Other fields of +condition are optional.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "expression": { + Type: schema.TypeString, + Required: true, + Description: `Textual representation of an expression in Common Expression Language syntax.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `Description of the expression. This is a longer text which describes the expression, +e.g. when hovered over it in a UI.`, + }, + "location": { + Type: schema.TypeString, + Optional: true, + Description: `String indicating the location of the expression for error reporting, e.g. a file +name and a position in the file.`, + }, + "title": { + Type: schema.TypeString, + Optional: true, + Description: `Title for the expression, i.e. a short string describing its purpose. +This can be used e.g. in UIs which allow to enter the expression.`, + }, + }, + }, + }, "content_type": { Type: schema.TypeString, Optional: true, @@ -159,6 +196,12 @@ func resourceCloudAssetProjectFeedCreate(d *schema.ResourceData, meta interface{ } else if v, ok := d.GetOkExists("feed_output_config"); !isEmptyValue(reflect.ValueOf(feedOutputConfigProp)) && (ok || !reflect.DeepEqual(v, feedOutputConfigProp)) { obj["feedOutputConfig"] = feedOutputConfigProp } + conditionProp, err := expandCloudAssetProjectFeedCondition(d.Get("condition"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("condition"); !isEmptyValue(reflect.ValueOf(conditionProp)) && (ok || !reflect.DeepEqual(v, conditionProp)) { + obj["condition"] = conditionProp + } obj, err = resourceCloudAssetProjectFeedEncoder(d, meta, obj) if err != nil { @@ -259,6 +302,9 @@ func resourceCloudAssetProjectFeedRead(d *schema.ResourceData, meta interface{}) if err := d.Set("feed_output_config", flattenCloudAssetProjectFeedFeedOutputConfig(res["feedOutputConfig"], d, config)); err != nil { return fmt.Errorf("Error reading ProjectFeed: %s", err) } + if err := d.Set("condition", flattenCloudAssetProjectFeedCondition(res["condition"], d, config)); err != nil { + return fmt.Errorf("Error reading ProjectFeed: %s", err) + } return nil } @@ -303,6 +349,12 @@ func resourceCloudAssetProjectFeedUpdate(d *schema.ResourceData, meta interface{ } else if v, ok := d.GetOkExists("feed_output_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, feedOutputConfigProp)) { obj["feedOutputConfig"] = feedOutputConfigProp } + conditionProp, err := expandCloudAssetProjectFeedCondition(d.Get("condition"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("condition"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, conditionProp)) { + obj["condition"] = conditionProp + } obj, err = resourceCloudAssetProjectFeedEncoder(d, meta, obj) if err != nil { @@ -332,6 +384,10 @@ func resourceCloudAssetProjectFeedUpdate(d *schema.ResourceData, meta interface{ if d.HasChange("feed_output_config") { updateMask = append(updateMask, "feedOutputConfig") } + + if d.HasChange("condition") { + updateMask = append(updateMask, "condition") + } // updateMask is a URL parameter but not present in the schema, so replaceVars // won't set it url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) @@ -445,6 +501,41 @@ func flattenCloudAssetProjectFeedFeedOutputConfigPubsubDestinationTopic(v interf return v } +func flattenCloudAssetProjectFeedCondition(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["expression"] = + flattenCloudAssetProjectFeedConditionExpression(original["expression"], d, config) + transformed["title"] = + flattenCloudAssetProjectFeedConditionTitle(original["title"], d, config) + transformed["description"] = + flattenCloudAssetProjectFeedConditionDescription(original["description"], d, config) + transformed["location"] = + flattenCloudAssetProjectFeedConditionLocation(original["location"], d, config) + return []interface{}{transformed} +} +func flattenCloudAssetProjectFeedConditionExpression(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetProjectFeedConditionTitle(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetProjectFeedConditionDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenCloudAssetProjectFeedConditionLocation(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func expandCloudAssetProjectFeedAssetNames(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -499,6 +590,62 @@ func expandCloudAssetProjectFeedFeedOutputConfigPubsubDestinationTopic(v interfa return v, nil } +func expandCloudAssetProjectFeedCondition(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedExpression, err := expandCloudAssetProjectFeedConditionExpression(original["expression"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedExpression); val.IsValid() && !isEmptyValue(val) { + transformed["expression"] = transformedExpression + } + + transformedTitle, err := expandCloudAssetProjectFeedConditionTitle(original["title"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTitle); val.IsValid() && !isEmptyValue(val) { + transformed["title"] = transformedTitle + } + + transformedDescription, err := expandCloudAssetProjectFeedConditionDescription(original["description"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) { + transformed["description"] = transformedDescription + } + + transformedLocation, err := expandCloudAssetProjectFeedConditionLocation(original["location"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLocation); val.IsValid() && !isEmptyValue(val) { + transformed["location"] = transformedLocation + } + + return transformed, nil +} + +func expandCloudAssetProjectFeedConditionExpression(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetProjectFeedConditionTitle(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetProjectFeedConditionDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudAssetProjectFeedConditionLocation(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func resourceCloudAssetProjectFeedEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { // Remove the "folders/" prefix from the folder ID if folder, ok := d.GetOkExists("folder"); ok { diff --git a/google-beta/resource_cloud_asset_project_feed_generated_test.go b/google-beta/resource_cloud_asset_project_feed_generated_test.go index 7a98f64e12..9c42f4d1ab 100644 --- a/google-beta/resource_cloud_asset_project_feed_generated_test.go +++ b/google-beta/resource_cloud_asset_project_feed_generated_test.go @@ -71,6 +71,15 @@ resource "google_cloud_asset_project_feed" "project_feed" { } } + condition { + expression = <<-EOT + !temporal_asset.deleted && + temporal_asset.prior_asset_state == google.cloud.asset.v1.TemporalAsset.PriorAssetState.DOES_NOT_EXIST + EOT + title = "created" + description = "Send notifications on creation events" + } + # Wait for the permission to be ready on the destination topic. depends_on = [ google_pubsub_topic_iam_member.cloud_asset_writer, diff --git a/website/docs/r/cloud_asset_folder_feed.html.markdown b/website/docs/r/cloud_asset_folder_feed.html.markdown index d47b207cab..5f0be725f3 100644 --- a/website/docs/r/cloud_asset_folder_feed.html.markdown +++ b/website/docs/r/cloud_asset_folder_feed.html.markdown @@ -59,6 +59,15 @@ resource "google_cloud_asset_folder_feed" "folder_feed" { } } + condition { + expression = <<-EOT + !temporal_asset.deleted && + temporal_asset.prior_asset_state == google.cloud.asset.v1.TemporalAsset.PriorAssetState.DOES_NOT_EXIST + EOT + title = "created" + description = "Send notifications on creation events" + } + # Wait for the permission to be ready on the destination topic. depends_on = [ google_pubsub_topic_iam_member.cloud_asset_writer, @@ -155,6 +164,36 @@ The `pubsub_destination` block supports: Asset content type. If not specified, no content but the asset name and type will be returned. Possible values are `CONTENT_TYPE_UNSPECIFIED`, `RESOURCE`, `IAM_POLICY`, `ORG_POLICY`, and `ACCESS_POLICY`. +* `condition` - + (Optional) + A condition which determines whether an asset update should be published. If specified, an asset + will be returned only when the expression evaluates to true. When set, expression field + must be a valid CEL expression on a TemporalAsset with name temporal_asset. Example: a Feed with + expression "temporal_asset.deleted == true" will only publish Asset deletions. Other fields of + condition are optional. + Structure is documented below. + + +The `condition` block supports: + +* `expression` - + (Required) + Textual representation of an expression in Common Expression Language syntax. + +* `title` - + (Optional) + Title for the expression, i.e. a short string describing its purpose. + This can be used e.g. in UIs which allow to enter the expression. + +* `description` - + (Optional) + Description of the expression. This is a longer text which describes the expression, + e.g. when hovered over it in a UI. + +* `location` - + (Optional) + String indicating the location of the expression for error reporting, e.g. a file + name and a position in the file. ## Attributes Reference diff --git a/website/docs/r/cloud_asset_organization_feed.html.markdown b/website/docs/r/cloud_asset_organization_feed.html.markdown index 48451eeb61..f59056cdd5 100644 --- a/website/docs/r/cloud_asset_organization_feed.html.markdown +++ b/website/docs/r/cloud_asset_organization_feed.html.markdown @@ -59,6 +59,15 @@ resource "google_cloud_asset_organization_feed" "organization_feed" { } } + condition { + expression = <<-EOT + !temporal_asset.deleted && + temporal_asset.prior_asset_state == google.cloud.asset.v1.TemporalAsset.PriorAssetState.DOES_NOT_EXIST + EOT + title = "created" + description = "Send notifications on creation events" + } + # Wait for the permission to be ready on the destination topic. depends_on = [ google_pubsub_topic_iam_member.cloud_asset_writer, @@ -149,6 +158,36 @@ The `pubsub_destination` block supports: Asset content type. If not specified, no content but the asset name and type will be returned. Possible values are `CONTENT_TYPE_UNSPECIFIED`, `RESOURCE`, `IAM_POLICY`, `ORG_POLICY`, and `ACCESS_POLICY`. +* `condition` - + (Optional) + A condition which determines whether an asset update should be published. If specified, an asset + will be returned only when the expression evaluates to true. When set, expression field + must be a valid CEL expression on a TemporalAsset with name temporal_asset. Example: a Feed with + expression "temporal_asset.deleted == true" will only publish Asset deletions. Other fields of + condition are optional. + Structure is documented below. + + +The `condition` block supports: + +* `expression` - + (Required) + Textual representation of an expression in Common Expression Language syntax. + +* `title` - + (Optional) + Title for the expression, i.e. a short string describing its purpose. + This can be used e.g. in UIs which allow to enter the expression. + +* `description` - + (Optional) + Description of the expression. This is a longer text which describes the expression, + e.g. when hovered over it in a UI. + +* `location` - + (Optional) + String indicating the location of the expression for error reporting, e.g. a file + name and a position in the file. ## Attributes Reference diff --git a/website/docs/r/cloud_asset_project_feed.html.markdown b/website/docs/r/cloud_asset_project_feed.html.markdown index e9fcf36ce6..9b3053a2c5 100644 --- a/website/docs/r/cloud_asset_project_feed.html.markdown +++ b/website/docs/r/cloud_asset_project_feed.html.markdown @@ -57,6 +57,15 @@ resource "google_cloud_asset_project_feed" "project_feed" { } } + condition { + expression = <<-EOT + !temporal_asset.deleted && + temporal_asset.prior_asset_state == google.cloud.asset.v1.TemporalAsset.PriorAssetState.DOES_NOT_EXIST + EOT + title = "created" + description = "Send notifications on creation events" + } + # Wait for the permission to be ready on the destination topic. depends_on = [ google_pubsub_topic_iam_member.cloud_asset_writer, @@ -144,10 +153,40 @@ The `pubsub_destination` block supports: Asset content type. If not specified, no content but the asset name and type will be returned. Possible values are `CONTENT_TYPE_UNSPECIFIED`, `RESOURCE`, `IAM_POLICY`, `ORG_POLICY`, and `ACCESS_POLICY`. +* `condition` - + (Optional) + A condition which determines whether an asset update should be published. If specified, an asset + will be returned only when the expression evaluates to true. When set, expression field + must be a valid CEL expression on a TemporalAsset with name temporal_asset. Example: a Feed with + expression "temporal_asset.deleted == true" will only publish Asset deletions. Other fields of + condition are optional. + Structure is documented below. + * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. +The `condition` block supports: + +* `expression` - + (Required) + Textual representation of an expression in Common Expression Language syntax. + +* `title` - + (Optional) + Title for the expression, i.e. a short string describing its purpose. + This can be used e.g. in UIs which allow to enter the expression. + +* `description` - + (Optional) + Description of the expression. This is a longer text which describes the expression, + e.g. when hovered over it in a UI. + +* `location` - + (Optional) + String indicating the location of the expression for error reporting, e.g. a file + name and a position in the file. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: