From 5da4f81889a28de65d609a40038b5b24465d0749 Mon Sep 17 00:00:00 2001 From: Jochen Rauschenbusch Date: Tue, 26 May 2020 22:51:03 +0200 Subject: [PATCH] `azurerm_eventgrid_topic` - support for `input_schema`, `input_mapping_fields`, and `input_mapping_default_values` (#6858) --- .../eventgrid/eventgrid_topic_resource.go | 242 +++++++++++++++++- .../tests/eventgrid_topic_resource_test.go | 49 ++++ website/docs/r/eventgrid_topic.html.markdown | 31 +++ 3 files changed, 321 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/eventgrid/eventgrid_topic_resource.go b/azurerm/internal/services/eventgrid/eventgrid_topic_resource.go index be5f023e351f..90e7f961c56e 100644 --- a/azurerm/internal/services/eventgrid/eventgrid_topic_resource.go +++ b/azurerm/internal/services/eventgrid/eventgrid_topic_resource.go @@ -51,6 +51,85 @@ func resourceArmEventGridTopic() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupName(), + "input_schema": { + Type: schema.TypeString, + Optional: true, + Default: string(eventgrid.InputSchemaEventGridSchema), + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(eventgrid.InputSchemaCloudEventSchemaV10), + string(eventgrid.InputSchemaCustomEventSchema), + string(eventgrid.InputSchemaEventGridSchema), + }, false), + }, + + "input_mapping_fields": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "event_time": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "event_type": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "subject": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "data_version": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + }, + }, + }, + + "input_mapping_default_values": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "event_type": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "subject": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "data_version": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + }, + }, + }, + "endpoint": { Type: schema.TypeString, Computed: true, @@ -97,9 +176,14 @@ func resourceArmEventGridTopicCreateUpdate(d *schema.ResourceData, meta interfac location := azure.NormalizeLocation(d.Get("location").(string)) t := d.Get("tags").(map[string]interface{}) + topicProperties := &eventgrid.TopicProperties{ + InputSchemaMapping: expandAzureRmEventgridTopicInputMapping(d), + InputSchema: eventgrid.InputSchema(d.Get("input_schema").(string)), + } + properties := eventgrid.Topic{ Location: &location, - TopicProperties: &eventgrid.TopicProperties{}, + TopicProperties: topicProperties, Tags: tags.Expand(t), } @@ -147,6 +231,27 @@ func resourceArmEventGridTopicRead(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Error making Read request on EventGrid Topic '%s': %+v", id.Name, err) } + if props := resp.TopicProperties; props != nil { + d.Set("endpoint", props.Endpoint) + + d.Set("input_schema", string(props.InputSchema)) + + inputMappingFields, err := flattenAzureRmEventgridTopicInputMapping(props.InputSchemaMapping) + if err != nil { + return fmt.Errorf("Unable to flatten `input_schema_mapping_fields` for EventGrid Topic %q (Resource Group %q): %s", id.Name, id.ResourceGroup, err) + } + if err := d.Set("input_mapping_fields", inputMappingFields); err != nil { + return fmt.Errorf("Error setting `input_schema_mapping_fields` for EventGrid Topic %q (Resource Group %q): %s", id.Name, id.ResourceGroup, err) + } + + inputMappingDefaultValues, err := flattenAzureRmEventgridTopicInputMappingDefaultValues(props.InputSchemaMapping) + if err != nil { + return fmt.Errorf("Unable to flatten `input_schema_mapping_default_values` for EventGrid Topic %q (Resource Group %q): %s", id.Name, id.ResourceGroup, err) + } + if err := d.Set("input_mapping_default_values", inputMappingDefaultValues); err != nil { + return fmt.Errorf("Error setting `input_schema_mapping_fields` for EventGrid Topic %q (Resource Group %q): %s", id.Name, id.ResourceGroup, err) + } + } keys, err := client.ListSharedAccessKeys(ctx, id.ResourceGroup, id.Name) if err != nil { @@ -196,3 +301,138 @@ func resourceArmEventGridTopicDelete(d *schema.ResourceData, meta interface{}) e return nil } + +func expandAzureRmEventgridTopicInputMapping(d *schema.ResourceData) *eventgrid.JSONInputSchemaMapping { + imf, imfok := d.GetOk("input_mapping_fields") + + imdv, imdvok := d.GetOk("input_mapping_default_values") + + if !imfok && !imdvok { + return nil + } + + jismp := eventgrid.JSONInputSchemaMappingProperties{} + + if imfok { + mappings := imf.([]interface{}) + if len(mappings) > 0 && mappings[0] != nil { + if mapping := mappings[0].(map[string]interface{}); mapping != nil { + if id := mapping["id"].(string); id != "" { + jismp.ID = &eventgrid.JSONField{SourceField: &id} + } + + if eventTime := mapping["event_time"].(string); eventTime != "" { + jismp.EventTime = &eventgrid.JSONField{SourceField: &eventTime} + } + + if topic := mapping["topic"].(string); topic != "" { + jismp.Topic = &eventgrid.JSONField{SourceField: &topic} + } + + if dataVersion := mapping["data_version"].(string); dataVersion != "" { + jismp.DataVersion = &eventgrid.JSONFieldWithDefault{SourceField: &dataVersion} + } + + if subject := mapping["subject"].(string); subject != "" { + jismp.Subject = &eventgrid.JSONFieldWithDefault{SourceField: &subject} + } + + if eventType := mapping["event_type"].(string); eventType != "" { + jismp.EventType = &eventgrid.JSONFieldWithDefault{SourceField: &eventType} + } + } + } + } + + if imdvok { + mappings := imdv.([]interface{}) + if len(mappings) > 0 && mappings[0] != nil { + if mapping := mappings[0].(map[string]interface{}); mapping != nil { + if dataVersion := mapping["data_version"].(string); dataVersion != "" { + jismp.DataVersion = &eventgrid.JSONFieldWithDefault{DefaultValue: &dataVersion} + } + + if subject := mapping["subject"].(string); subject != "" { + jismp.Subject = &eventgrid.JSONFieldWithDefault{DefaultValue: &subject} + } + + if eventType := mapping["event_type"].(string); eventType != "" { + jismp.EventType = &eventgrid.JSONFieldWithDefault{DefaultValue: &eventType} + } + } + } + } + + jsonMapping := eventgrid.JSONInputSchemaMapping{ + JSONInputSchemaMappingProperties: &jismp, + InputSchemaMappingType: eventgrid.InputSchemaMappingTypeJSON, + } + + return &jsonMapping +} + +func flattenAzureRmEventgridTopicInputMapping(input eventgrid.BasicInputSchemaMapping) ([]interface{}, error) { + if input == nil { + return nil, nil + } + result := make(map[string]interface{}) + + jsonValues, ok := input.(eventgrid.JSONInputSchemaMapping) + if !ok { + return nil, fmt.Errorf("Unable to read JSONInputSchemaMapping") + } + props := jsonValues.JSONInputSchemaMappingProperties + + if props.EventTime != nil && props.EventTime.SourceField != nil { + result["event_time"] = *props.EventTime.SourceField + } + + if props.ID != nil && props.ID.SourceField != nil { + result["id"] = *props.ID.SourceField + } + + if props.Topic != nil && props.Topic.SourceField != nil { + result["topic"] = *props.Topic.SourceField + } + + if props.DataVersion != nil && props.DataVersion.SourceField != nil { + result["data_version"] = *props.DataVersion.SourceField + } + + if props.EventType != nil && props.EventType.SourceField != nil { + result["event_type"] = *props.EventType.SourceField + } + + if props.Subject != nil && props.Subject.SourceField != nil { + result["subject"] = *props.Subject.SourceField + } + + return []interface{}{result}, nil +} + +func flattenAzureRmEventgridTopicInputMappingDefaultValues(input eventgrid.BasicInputSchemaMapping) ([]interface{}, error) { + if input == nil { + return nil, nil + } + result := make(map[string]interface{}) + + jsonValues, ok := input.(eventgrid.JSONInputSchemaMapping) + if !ok { + return nil, fmt.Errorf("Unable to read JSONInputSchemaMapping") + } + props := jsonValues.JSONInputSchemaMappingProperties + + if props.DataVersion != nil && props.DataVersion.DefaultValue != nil { + result["data_version"] = *props.DataVersion.DefaultValue + } + + if props.EventType != nil && props.EventType.DefaultValue != nil { + result["event_type"] = *props.EventType.DefaultValue + } + + if props.Subject != nil && props.Subject.DefaultValue != nil { + result["subject"] = *props.Subject.DefaultValue + } + + return []interface{}{result}, nil +} diff --git a/azurerm/internal/services/eventgrid/tests/eventgrid_topic_resource_test.go b/azurerm/internal/services/eventgrid/tests/eventgrid_topic_resource_test.go index d2c9873d58bf..5b06f0fbf10d 100644 --- a/azurerm/internal/services/eventgrid/tests/eventgrid_topic_resource_test.go +++ b/azurerm/internal/services/eventgrid/tests/eventgrid_topic_resource_test.go @@ -56,6 +56,29 @@ func TestAccAzureRMEventGridTopic_requiresImport(t *testing.T) { }) } +func TestAccAzureRMEventGridTopic_mapping(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_topic", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMEventGridTopicDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMEventGridTopic_mapping(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMEventGridTopicExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "input_mapping_fields.0.topic", "test"), + resource.TestCheckResourceAttr(data.ResourceName, "input_mapping_fields.0.topic", "test"), + resource.TestCheckResourceAttr(data.ResourceName, "input_mapping_default_values.0.data_version", "1.0"), + resource.TestCheckResourceAttr(data.ResourceName, "input_mapping_default_values.0.subject", "DefaultSubject"), + ), + }, + data.ImportStep(), + }, + }) +} + func TestAccAzureRMEventGridTopic_basicWithTags(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_eventgrid_topic", "test") @@ -174,6 +197,32 @@ resource "azurerm_eventgrid_topic" "import" { `, template) } +func testAccAzureRMEventGridTopic_mapping(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} +resource "azurerm_eventgrid_topic" "test" { + name = "acctesteg-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + input_schema = "CustomEventSchema" + input_mapping_fields { + topic = "test" + event_type = "test" + } + input_mapping_default_values { + data_version = "1.0" + subject = "DefaultSubject" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + func testAccAzureRMEventGridTopic_basicWithTags(data acceptance.TestData) string { // currently only supported in "West Central US" & "West US 2" location := "westus2" diff --git a/website/docs/r/eventgrid_topic.html.markdown b/website/docs/r/eventgrid_topic.html.markdown index 5d37e8c1102e..0d3ee8b160fd 100644 --- a/website/docs/r/eventgrid_topic.html.markdown +++ b/website/docs/r/eventgrid_topic.html.markdown @@ -42,7 +42,38 @@ The following arguments are supported: * `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. +* `input_schema` - (Optional) Specifies the schema in which incoming events will be published to this domain. Allowed values are `CloudEventSchemaV1_0`, `CustomEventSchema`, or `EventGridSchema`. Defaults to `EventGridSchema`. Changing this forces a new resource to be created. + +* `input_mapping_fields` - (Optional) A `input_mapping_fields` block as defined below. + +* `input_mapping_default_values` - (Optional) A `input_mapping_default_values` block as defined below. + * `tags` - (Optional) A mapping of tags to assign to the resource. +--- + +A `input_mapping_fields` supports the following: + +* `id` - (Optional) Specifies the id of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +* `topic` - (Optional) Specifies the topic of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +* `event_type` - (Optional) Specifies the event type of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +* `event_time` - (Optional) Specifies the event time of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +* `data_version` - (Optional) Specifies the data version of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +* `subject` - (Optional) Specifies the subject of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +--- + +A `input_mapping_default_values` supports the following: + +* `event_type` - (Optional) Specifies the default event type of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +* `data_version` - (Optional) Specifies the default data version of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. + +* `subject` - (Optional) Specifies the default subject of the EventGrid Event to associate with the domain. Changing this forces a new resource to be created. ## Attributes Reference