diff --git a/internal/services/eventgrid/event_subscription.go b/internal/services/eventgrid/event_subscription.go index 7da48980d919..d130b020003f 100644 --- a/internal/services/eventgrid/event_subscription.go +++ b/internal/services/eventgrid/event_subscription.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -89,6 +90,47 @@ func eventSubscriptionSchemaEventDeliverySchema() *pluginsdk.Schema { } } +func eventSubscriptionSchemaDeliveryProperty() *pluginsdk.Schema { + return &pluginsdk.Schema{ + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "header_name": { + Type: pluginsdk.TypeString, + Required: true, + DiffSuppressFunc: suppress.CaseDifference, + }, + + "type": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "Static", + "Dynamic", + }, false), + }, + + "value": { + Type: pluginsdk.TypeString, + Optional: true, + Sensitive: true, + }, + + "source_field": { + Type: pluginsdk.TypeString, + Optional: true, + }, + + "secret": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + }, + }, + } +} + func eventSubscriptionSchemaExpirationTimeUTC() *pluginsdk.Schema { return &pluginsdk.Schema{ Type: pluginsdk.TypeString, @@ -816,61 +858,73 @@ func expandEventGridExpirationTime(d *schema.ResourceData) (*date.Time, error) { } func expandEventGridEventSubscriptionDestination(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { - if v, ok := d.GetOk("azure_function_endpoint"); ok { - return expandEventGridEventSubscriptionAzureFunctionEndpoint(v) + if _, ok := d.GetOk("azure_function_endpoint"); ok { + return expandEventGridEventSubscriptionAzureFunctionEndpoint(d) } - if v, ok := d.GetOk("eventhub_endpoint_id"); ok { - return &eventgrid.EventHubEventSubscriptionDestination{ - EndpointType: eventgrid.EndpointTypeEventHub, - EventHubEventSubscriptionDestinationProperties: &eventgrid.EventHubEventSubscriptionDestinationProperties{ - ResourceID: utils.String(v.(string)), - }, - } + if _, ok := d.GetOk("eventhub_endpoint_id"); ok { + return expandEventGridEventSubscriptionEventhubEndpoint(d) } else if _, ok := d.GetOk("eventhub_endpoint"); ok { return expandEventGridEventSubscriptionEventhubEndpoint(d) } - if v, ok := d.GetOk("hybrid_connection_endpoint_id"); ok { - return &eventgrid.HybridConnectionEventSubscriptionDestination{ - EndpointType: eventgrid.EndpointTypeHybridConnection, - HybridConnectionEventSubscriptionDestinationProperties: &eventgrid.HybridConnectionEventSubscriptionDestinationProperties{ - ResourceID: utils.String(v.(string)), - }, - } + if _, ok := d.GetOk("hybrid_connection_endpoint_id"); ok { + return expandEventGridEventSubscriptionHybridConnectionEndpoint(d) } else if _, ok := d.GetOk("hybrid_connection_endpoint"); ok { return expandEventGridEventSubscriptionHybridConnectionEndpoint(d) } - if v, ok := d.GetOk("service_bus_queue_endpoint_id"); ok { - return &eventgrid.ServiceBusQueueEventSubscriptionDestination{ - EndpointType: eventgrid.EndpointTypeServiceBusQueue, - ServiceBusQueueEventSubscriptionDestinationProperties: &eventgrid.ServiceBusQueueEventSubscriptionDestinationProperties{ - ResourceID: utils.String(v.(string)), - }, - } + if _, ok := d.GetOk("service_bus_queue_endpoint_id"); ok { + return expandEventGridEventSubscriptionServiceBusQueueEndpoint(d) } - if v, ok := d.GetOk("service_bus_topic_endpoint_id"); ok { - return &eventgrid.ServiceBusTopicEventSubscriptionDestination{ - EndpointType: eventgrid.EndpointTypeServiceBusTopic, - ServiceBusTopicEventSubscriptionDestinationProperties: &eventgrid.ServiceBusTopicEventSubscriptionDestinationProperties{ - ResourceID: utils.String(v.(string)), - }, - } + if _, ok := d.GetOk("service_bus_topic_endpoint_id"); ok { + return expandEventGridEventSubscriptionServiceBusTopicEndpoint(d) } if _, ok := d.GetOk("storage_queue_endpoint"); ok { return expandEventGridEventSubscriptionStorageQueueEndpoint(d) } - if v, ok := d.GetOk("webhook_endpoint"); ok { - return expandEventGridEventSubscriptionWebhookEndpoint(v) + if _, ok := d.GetOk("webhook_endpoint"); ok { + return expandEventGridEventSubscriptionWebhookEndpoint(d) } return nil } +func expandEventGridEventSubscriptionServiceBusQueueEndpoint(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { + endpoint := d.Get("service_bus_queue_endpoint_id") + + props := &eventgrid.ServiceBusQueueEventSubscriptionDestinationProperties{ + ResourceID: utils.String(endpoint.(string)), + } + + deliveryMappings := expandDeliveryProperties(d) + props.DeliveryAttributeMappings = &deliveryMappings + + return &eventgrid.ServiceBusQueueEventSubscriptionDestination{ + EndpointType: eventgrid.EndpointTypeServiceBusQueue, + ServiceBusQueueEventSubscriptionDestinationProperties: props, + } +} + +func expandEventGridEventSubscriptionServiceBusTopicEndpoint(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { + endpoint := d.Get("service_bus_topic_endpoint_id") + + props := &eventgrid.ServiceBusTopicEventSubscriptionDestinationProperties{ + ResourceID: utils.String(endpoint.(string)), + } + + deliveryMappings := expandDeliveryProperties(d) + props.DeliveryAttributeMappings = &deliveryMappings + + return &eventgrid.ServiceBusTopicEventSubscriptionDestination{ + EndpointType: eventgrid.EndpointTypeServiceBusTopic, + ServiceBusTopicEventSubscriptionDestinationProperties: props, + } +} + func expandEventGridEventSubscriptionStorageQueueEndpoint(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { props := d.Get("storage_queue_endpoint").([]interface{})[0].(map[string]interface{}) storageAccountID := props["storage_account_id"].(string) @@ -886,38 +940,59 @@ func expandEventGridEventSubscriptionStorageQueueEndpoint(d *pluginsdk.ResourceD } func expandEventGridEventSubscriptionEventhubEndpoint(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { - ep := d.Get("eventhub_endpoint").([]interface{}) - if len(ep) == 0 || ep[0] == nil { - return eventgrid.EventHubEventSubscriptionDestination{} + + destinationProps := &eventgrid.EventHubEventSubscriptionDestinationProperties{} + + if _, ok := d.GetOk("eventhub_endpoint_id"); ok { + endpoint := d.Get("eventhub_endpoint_id") + destinationProps.ResourceID = utils.String(endpoint.(string)) + } else if _, ok := d.GetOk("eventhub_endpoint"); ok { + ep := d.Get("eventhub_endpoint").([]interface{}) + if len(ep) == 0 || ep[0] == nil { + return eventgrid.EventHubEventSubscriptionDestination{} + } + props := ep[0].(map[string]interface{}) + eventHubID := props["eventhub_id"].(string) + destinationProps.ResourceID = &eventHubID } - props := ep[0].(map[string]interface{}) - eventHubID := props["eventhub_id"].(string) + + deliveryMappings := expandDeliveryProperties(d) + destinationProps.DeliveryAttributeMappings = &deliveryMappings return eventgrid.EventHubEventSubscriptionDestination{ EndpointType: eventgrid.EndpointTypeEventHub, - EventHubEventSubscriptionDestinationProperties: &eventgrid.EventHubEventSubscriptionDestinationProperties{ - ResourceID: &eventHubID, - }, + EventHubEventSubscriptionDestinationProperties: destinationProps, } } func expandEventGridEventSubscriptionHybridConnectionEndpoint(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { - ep := d.Get("hybrid_connection_endpoint").([]interface{}) - if len(ep) == 0 || ep[0] == nil { - return eventgrid.HybridConnectionEventSubscriptionDestination{} + + destinationProps := &eventgrid.HybridConnectionEventSubscriptionDestinationProperties{} + + if v, ok := d.GetOk("hybrid_connection_endpoint_id"); ok { + destinationProps.ResourceID = utils.String(v.(string)) + } else if _, ok := d.GetOk("hybrid_connection_endpoint"); ok { + ep := d.Get("hybrid_connection_endpoint").([]interface{}) + if len(ep) == 0 || ep[0] == nil { + return eventgrid.HybridConnectionEventSubscriptionDestination{} + } + props := ep[0].(map[string]interface{}) + hybridConnectionID := props["hybrid_connection_id"].(string) + destinationProps.ResourceID = &hybridConnectionID } - props := ep[0].(map[string]interface{}) - hybridConnectionID := props["hybrid_connection_id"].(string) + + deliveryMappings := expandDeliveryProperties(d) + destinationProps.DeliveryAttributeMappings = &deliveryMappings return eventgrid.HybridConnectionEventSubscriptionDestination{ EndpointType: eventgrid.EndpointTypeHybridConnection, - HybridConnectionEventSubscriptionDestinationProperties: &eventgrid.HybridConnectionEventSubscriptionDestinationProperties{ - ResourceID: &hybridConnectionID, - }, + HybridConnectionEventSubscriptionDestinationProperties: destinationProps, } } -func expandEventGridEventSubscriptionAzureFunctionEndpoint(input interface{}) eventgrid.BasicEventSubscriptionDestination { +func expandEventGridEventSubscriptionAzureFunctionEndpoint(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { + + input := d.Get("azure_function_endpoint") configs := input.([]interface{}) props := eventgrid.AzureFunctionEventSubscriptionDestinationProperties{} @@ -944,10 +1019,55 @@ func expandEventGridEventSubscriptionAzureFunctionEndpoint(input interface{}) ev props.PreferredBatchSizeInKilobytes = utils.Int32(int32(v.(int))) } + deliveryMappings := expandDeliveryProperties(d) + props.DeliveryAttributeMappings = &deliveryMappings + return azureFunctionDestination } -func expandEventGridEventSubscriptionWebhookEndpoint(input interface{}) eventgrid.BasicEventSubscriptionDestination { +func expandDeliveryProperties(d *pluginsdk.ResourceData) []eventgrid.BasicDeliveryAttributeMapping { + + var basicDeliveryAttributeMapping []eventgrid.BasicDeliveryAttributeMapping + + deliveryMappingsConfig, deliveryMappingsExists := d.GetOk("delivery_property") + if !deliveryMappingsExists { + return basicDeliveryAttributeMapping + } + + input := deliveryMappingsConfig.([]interface{}) + if len(input) == 0 { + return basicDeliveryAttributeMapping + } + + for _, r := range input { + mappingBlock := r.(map[string]interface{}) + + if mappingBlock["type"].(string) == "Static" { + basicDeliveryAttributeMapping = append(basicDeliveryAttributeMapping, eventgrid.StaticDeliveryAttributeMapping{ + Name: utils.String(mappingBlock["header_name"].(string)), + Type: eventgrid.TypeStatic, + StaticDeliveryAttributeMappingProperties: &eventgrid.StaticDeliveryAttributeMappingProperties{ + Value: utils.String(mappingBlock["value"].(string)), + IsSecret: utils.Bool(mappingBlock["secret"].(bool)), + }, + }) + } else if mappingBlock["type"].(string) == "Dynamic" { + basicDeliveryAttributeMapping = append(basicDeliveryAttributeMapping, eventgrid.DynamicDeliveryAttributeMapping{ + Name: utils.String(mappingBlock["header_name"].(string)), + Type: eventgrid.TypeDynamic, + DynamicDeliveryAttributeMappingProperties: &eventgrid.DynamicDeliveryAttributeMappingProperties{ + SourceField: utils.String(mappingBlock["source_field"].(string)), + }, + }) + } + } + + return basicDeliveryAttributeMapping +} + +func expandEventGridEventSubscriptionWebhookEndpoint(d *pluginsdk.ResourceData) eventgrid.BasicEventSubscriptionDestination { + + input := d.Get("webhook_endpoint") configs := input.([]interface{}) props := eventgrid.WebHookEventSubscriptionDestinationProperties{} @@ -982,6 +1102,9 @@ func expandEventGridEventSubscriptionWebhookEndpoint(input interface{}) eventgri props.AzureActiveDirectoryApplicationIDOrURI = utils.String(v.(string)) } + deliveryMappings := expandDeliveryProperties(d) + props.DeliveryAttributeMappings = &deliveryMappings + return webhookDestination } @@ -1150,6 +1273,58 @@ func flattenEventGridEventSubscriptionEventhubEndpoint(input *eventgrid.EventHub return []interface{}{result} } +func flattenDeliveryProperties(d *pluginsdk.ResourceData, input *[]eventgrid.BasicDeliveryAttributeMapping) []interface{} { + if input == nil { + return nil + } + + deliveryProperties := make([]interface{}, len(*input)) + for i, element := range *input { + attributeMapping := make(map[string]interface{}) + + if staticMapping, ok := element.AsStaticDeliveryAttributeMapping(); ok { + + attributeMapping["type"] = staticMapping.Type + if staticMapping.Name != nil { + attributeMapping["header_name"] = staticMapping.Name + } + if staticMapping.IsSecret != nil { + attributeMapping["secret"] = staticMapping.IsSecret + } + + if *staticMapping.IsSecret { + // If this is a secret, the Azure API just returns a value of 'Hidden', + // so we need to lookup the value that was provided from config to return + propertiesFromConfig := expandDeliveryProperties(d) + for _, v := range propertiesFromConfig { + if configMap, ok := v.AsStaticDeliveryAttributeMapping(); ok { + if *configMap.Name == *staticMapping.Name { + if configMap.Value != nil { + attributeMapping["value"] = configMap.Value + } + break + } + } + } + } else { + attributeMapping["value"] = staticMapping.Value + } + } else if dynamicMapping, ok := element.AsDynamicDeliveryAttributeMapping(); ok { + attributeMapping["type"] = dynamicMapping.Type + if dynamicMapping.Name != nil { + attributeMapping["header_name"] = dynamicMapping.Name + } + if dynamicMapping.SourceField != nil { + attributeMapping["source_field"] = dynamicMapping.SourceField + } + } + + deliveryProperties[i] = attributeMapping + } + + return deliveryProperties +} + func flattenEventGridEventSubscriptionHybridConnectionEndpoint(input *eventgrid.HybridConnectionEventSubscriptionDestination) []interface{} { if input == nil { return nil diff --git a/internal/services/eventgrid/eventgrid_event_subscription_resource.go b/internal/services/eventgrid/eventgrid_event_subscription_resource.go index 7628cc0434f3..1300b52f0ce1 100644 --- a/internal/services/eventgrid/eventgrid_event_subscription_resource.go +++ b/internal/services/eventgrid/eventgrid_event_subscription_resource.go @@ -151,6 +151,8 @@ func resourceEventGridEventSubscription() *pluginsdk.Resource { "labels": eventSubscriptionSchemaLabels(), "advanced_filtering_on_arrays_enabled": eventSubscriptionSchemaEnableAdvancedFilteringOnArrays(), + + "delivery_property": eventSubscriptionSchemaDeliveryProperty(), }, } } @@ -299,6 +301,12 @@ func resourceEventGridEventSubscriptionRead(d *pluginsdk.ResourceData, meta inte if err := d.Set("azure_function_endpoint", flattenEventGridEventSubscriptionAzureFunctionEndpoint(azureFunctionEndpoint)); err != nil { return fmt.Errorf("setting `%q` for EventGrid Event Subscription %q (Scope %q): %s", "azure_function_endpoint", id.Name, id.Scope, err) } + + if azureFunctionEndpoint.DeliveryAttributeMappings != nil { + if err := d.Set("delivery_property", flattenDeliveryProperties(d, azureFunctionEndpoint.DeliveryAttributeMappings)); err != nil { + return fmt.Errorf("setting `%q` for EventGrid delivery properties %q (Scope %q): %s", "azure_function_endpoint", id.Name, id.Scope, err) + } + } } if v, ok := destination.AsEventHubEventSubscriptionDestination(); ok { if err := d.Set("eventhub_endpoint_id", v.ResourceID); err != nil { @@ -308,6 +316,12 @@ func resourceEventGridEventSubscriptionRead(d *pluginsdk.ResourceData, meta inte if err := d.Set("eventhub_endpoint", flattenEventGridEventSubscriptionEventhubEndpoint(v)); err != nil { return fmt.Errorf("setting `%q` for EventGrid Event Subscription %q (Scope %q): %s", "eventhub_endpoint", id.Name, id.Scope, err) } + + if v.DeliveryAttributeMappings != nil { + if err := d.Set("delivery_property", flattenDeliveryProperties(d, v.DeliveryAttributeMappings)); err != nil { + return fmt.Errorf("setting `%q` for EventGrid delivery properties %q (Scope %q): %s", "eventhub_endpoint", id.Name, id.Scope, err) + } + } } if v, ok := destination.AsHybridConnectionEventSubscriptionDestination(); ok { if err := d.Set("hybrid_connection_endpoint_id", v.ResourceID); err != nil { @@ -317,6 +331,12 @@ func resourceEventGridEventSubscriptionRead(d *pluginsdk.ResourceData, meta inte if err := d.Set("hybrid_connection_endpoint", flattenEventGridEventSubscriptionHybridConnectionEndpoint(v)); err != nil { return fmt.Errorf("setting `%q` for EventGrid Event Subscription %q (Scope %q): %s", "hybrid_connection_endpoint", id.Name, id.Scope, err) } + + if v.DeliveryAttributeMappings != nil { + if err := d.Set("delivery_property", flattenDeliveryProperties(d, v.DeliveryAttributeMappings)); err != nil { + return fmt.Errorf("setting `%q` for EventGrid delivery properties %q (Scope %q): %s", "hybrid_connection_endpoint", id.Name, id.Scope, err) + } + } } if serviceBusQueueEndpoint, ok := destination.AsServiceBusQueueEventSubscriptionDestination(); ok { if err := d.Set("service_bus_queue_endpoint_id", serviceBusQueueEndpoint.ResourceID); err != nil { @@ -327,6 +347,11 @@ func resourceEventGridEventSubscriptionRead(d *pluginsdk.ResourceData, meta inte if err := d.Set("service_bus_topic_endpoint_id", serviceBusTopicEndpoint.ResourceID); err != nil { return fmt.Errorf("setting `%q` for EventGrid Event Subscription %q (Scope %q): %s", "service_bus_topic_endpoint_id", id.Name, id.Scope, err) } + if serviceBusTopicEndpoint.DeliveryAttributeMappings != nil { + if err := d.Set("delivery_property", flattenDeliveryProperties(d, serviceBusTopicEndpoint.DeliveryAttributeMappings)); err != nil { + return fmt.Errorf("setting `%q` for EventGrid delivery properties %q (Scope %q): %s", "service_bus_topic_endpoint_id", id.Name, id.Scope, err) + } + } } if v, ok := destination.AsStorageQueueEventSubscriptionDestination(); ok { if err := d.Set("storage_queue_endpoint", flattenEventGridEventSubscriptionStorageQueueEndpoint(v)); err != nil { @@ -341,6 +366,12 @@ func resourceEventGridEventSubscriptionRead(d *pluginsdk.ResourceData, meta inte if err := d.Set("webhook_endpoint", flattenEventGridEventSubscriptionWebhookEndpoint(v, &fullURL)); err != nil { return fmt.Errorf("setting `%q` for EventGrid Event Subscription %q (Scope %q): %s", "webhook_endpoint", id.Name, id.Scope, err) } + + if v.DeliveryAttributeMappings != nil { + if err := d.Set("delivery_property", flattenDeliveryProperties(d, v.DeliveryAttributeMappings)); err != nil { + return fmt.Errorf("setting `%q` for EventGrid delivery properties %q (Scope %q): %s", "webhook_endpoint", id.Name, id.Scope, err) + } + } } deadLetterDestination := props.DeadLetterDestination diff --git a/internal/services/eventgrid/eventgrid_event_subscription_resource_test.go b/internal/services/eventgrid/eventgrid_event_subscription_resource_test.go index b8b127b993c6..4831deca468c 100644 --- a/internal/services/eventgrid/eventgrid_event_subscription_resource_test.go +++ b/internal/services/eventgrid/eventgrid_event_subscription_resource_test.go @@ -188,6 +188,161 @@ func TestAccEventGridEventSubscription_advancedFilterMaxItems(t *testing.T) { }) } +func TestAccEventGridEventSubscription_deliveryPropertiesStatic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_event_subscription", "test") + r := EventGridEventSubscriptionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.deliveryProperties(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + + check.That(data.ResourceName).Key("delivery_property.0.header_name").HasValue("test-1"), + check.That(data.ResourceName).Key("delivery_property.0.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.0.value").HasValue("1"), + check.That(data.ResourceName).Key("delivery_property.0.secret").HasValue("false"), + + check.That(data.ResourceName).Key("delivery_property.1.header_name").HasValue("test-2"), + check.That(data.ResourceName).Key("delivery_property.1.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.1.value").HasValue("string"), + check.That(data.ResourceName).Key("delivery_property.1.secret").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccEventGridEventSubscription_deliveryPropertiesMixed(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_event_subscription", "test") + r := EventGridEventSubscriptionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.deliveryPropertiesWithMultipleTypes(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + + check.That(data.ResourceName).Key("delivery_property.0.header_name").HasValue("test-static-1"), + check.That(data.ResourceName).Key("delivery_property.0.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.0.value").HasValue("1"), + check.That(data.ResourceName).Key("delivery_property.0.secret").HasValue("false"), + + check.That(data.ResourceName).Key("delivery_property.1.header_name").HasValue("test-dynamic-1"), + check.That(data.ResourceName).Key("delivery_property.1.type").HasValue("Dynamic"), + check.That(data.ResourceName).Key("delivery_property.1.source_field").HasValue("data.system"), + + check.That(data.ResourceName).Key("delivery_property.2.header_name").HasValue("test-secret-1"), + check.That(data.ResourceName).Key("delivery_property.2.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.2.secret").HasValue("true"), + check.That(data.ResourceName).Key("delivery_property.2.value").HasValue("this-value-is-secret!"), + ), + }, + data.ImportStep("delivery_property.2.value"), + }) +} + +func TestAccEventGridEventSubscription_deliveryPropertiesSecret(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_event_subscription", "test") + r := EventGridEventSubscriptionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.deliveryPropertiesSecret(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + + check.That(data.ResourceName).Key("delivery_property.0.header_name").HasValue("test-secret-1"), + check.That(data.ResourceName).Key("delivery_property.0.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.0.secret").HasValue("true"), + ), + }, + data.ImportStep("delivery_property.0.value"), + }) +} + +func TestAccEventGridEventSubscription_deliveryPropertiesHybridRelay(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_event_subscription", "test") + r := EventGridEventSubscriptionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.deliveryPropertiesForHybridRelay(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + + check.That(data.ResourceName).Key("delivery_property.0.header_name").HasValue("test-static-1"), + check.That(data.ResourceName).Key("delivery_property.0.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.0.value").HasValue("1"), + check.That(data.ResourceName).Key("delivery_property.0.secret").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccEventGridEventSubscription_deliveryPropertiesForEventHubs(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_event_subscription", "test") + r := EventGridEventSubscriptionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.deliveryPropertiesForEventHubs(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + + check.That(data.ResourceName).Key("delivery_property.0.header_name").HasValue("test-static-1"), + check.That(data.ResourceName).Key("delivery_property.0.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.0.value").HasValue("1"), + check.That(data.ResourceName).Key("delivery_property.0.secret").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccEventGridEventSubscription_deliveryPropertiesUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_eventgrid_event_subscription", "test") + r := EventGridEventSubscriptionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.deliveryPropertiesWithMultipleTypes(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("delivery_property.0.header_name").HasValue("test-static-1"), + check.That(data.ResourceName).Key("delivery_property.0.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.0.value").HasValue("1"), + check.That(data.ResourceName).Key("delivery_property.0.secret").HasValue("false"), + check.That(data.ResourceName).Key("delivery_property.1.header_name").HasValue("test-dynamic-1"), + check.That(data.ResourceName).Key("delivery_property.1.type").HasValue("Dynamic"), + check.That(data.ResourceName).Key("delivery_property.1.source_field").HasValue("data.system"), + check.That(data.ResourceName).Key("delivery_property.2.header_name").HasValue("test-secret-1"), + check.That(data.ResourceName).Key("delivery_property.2.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.2.secret").HasValue("true"), + check.That(data.ResourceName).Key("delivery_property.2.value").HasValue("this-value-is-secret!"), + ), + }, + { + Config: r.deliveryPropertiesUpdate(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("delivery_property.0.header_name").HasValue("test-static-1"), + check.That(data.ResourceName).Key("delivery_property.0.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.0.value").HasValue("2"), + check.That(data.ResourceName).Key("delivery_property.0.secret").HasValue("false"), + check.That(data.ResourceName).Key("delivery_property.1.header_name").HasValue("test-dynamic-1"), + check.That(data.ResourceName).Key("delivery_property.1.type").HasValue("Dynamic"), + check.That(data.ResourceName).Key("delivery_property.1.source_field").HasValue("data.topic"), + check.That(data.ResourceName).Key("delivery_property.2.header_name").HasValue("test-secret-1"), + check.That(data.ResourceName).Key("delivery_property.2.type").HasValue("Static"), + check.That(data.ResourceName).Key("delivery_property.2.secret").HasValue("true"), + check.That(data.ResourceName).Key("delivery_property.2.value").HasValue("this-value-is-still-secret!"), + ), + }, + }) +} + func TestAccEventGridEventSubscription_identity(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_eventgrid_event_subscription", "test") r := EventGridEventSubscriptionResource{} @@ -822,3 +977,309 @@ resource "azurerm_eventgrid_event_subscription" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomString) } + +func (EventGridEventSubscriptionResource) deliveryProperties(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-eg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_servicebus_namespace" "example" { + name = "acctestservicebusnamespace-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" +} +resource "azurerm_servicebus_topic" "test" { + name = "acctestservicebustopic-%[1]d" + resource_group_name = azurerm_resource_group.test.name + namespace_name = azurerm_servicebus_namespace.example.name + enable_partitioning = true +} + +resource "azurerm_eventgrid_event_subscription" "test" { + name = "acctest-eg-%[1]d" + scope = azurerm_resource_group.test.id + + service_bus_topic_endpoint_id = azurerm_servicebus_topic.test.id + + advanced_filtering_on_arrays_enabled = true + + subject_filter { + subject_begins_with = "test/test" + } + + delivery_property { + header_name = "test-1" + type = "Static" + value = "1" + secret = false + } + + delivery_property { + header_name = "test-2" + type = "Static" + value = "string" + secret = false + } + +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} + +func (EventGridEventSubscriptionResource) deliveryPropertiesSecret(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-eg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_servicebus_namespace" "example" { + name = "acctestservicebusnamespace-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" +} +resource "azurerm_servicebus_topic" "test" { + name = "acctestservicebustopic-%[1]d" + resource_group_name = azurerm_resource_group.test.name + namespace_name = azurerm_servicebus_namespace.example.name + enable_partitioning = true +} + +resource "azurerm_eventgrid_event_subscription" "test" { + name = "acctest-eg-%[1]d" + scope = azurerm_resource_group.test.id + + service_bus_topic_endpoint_id = azurerm_servicebus_topic.test.id + + advanced_filtering_on_arrays_enabled = true + + subject_filter { + subject_begins_with = "test/test" + } + + delivery_property { + header_name = "test-secret-1" + type = "Static" + value = "1" + secret = true + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} + +func (EventGridEventSubscriptionResource) deliveryPropertiesWithMultipleTypes(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-eg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_servicebus_namespace" "example" { + name = "acctestservicebusnamespace-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" +} +resource "azurerm_servicebus_topic" "test" { + name = "acctestservicebustopic-%[1]d" + resource_group_name = azurerm_resource_group.test.name + namespace_name = azurerm_servicebus_namespace.example.name + enable_partitioning = true +} + +resource "azurerm_eventgrid_event_subscription" "test" { + name = "acctest-eg-%[1]d" + scope = azurerm_resource_group.test.id + + service_bus_topic_endpoint_id = azurerm_servicebus_topic.test.id + + advanced_filtering_on_arrays_enabled = true + + subject_filter { + subject_begins_with = "test/test" + } + + delivery_property { + header_name = "test-static-1" + type = "Static" + value = "1" + secret = false + } + + delivery_property { + header_name = "test-dynamic-1" + type = "Dynamic" + source_field = "data.system" + } + + delivery_property { + header_name = "test-secret-1" + type = "Static" + value = "this-value-is-secret!" + secret = true + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} + +func (EventGridEventSubscriptionResource) deliveryPropertiesUpdate(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-eg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_servicebus_namespace" "example" { + name = "acctestservicebusnamespace-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Standard" +} +resource "azurerm_servicebus_topic" "test" { + name = "acctestservicebustopic-%[1]d" + resource_group_name = azurerm_resource_group.test.name + namespace_name = azurerm_servicebus_namespace.example.name + enable_partitioning = true +} + +resource "azurerm_eventgrid_event_subscription" "test" { + name = "acctest-eg-%[1]d" + scope = azurerm_resource_group.test.id + + service_bus_topic_endpoint_id = azurerm_servicebus_topic.test.id + + advanced_filtering_on_arrays_enabled = true + + subject_filter { + subject_begins_with = "test/test" + } + + delivery_property { + header_name = "test-static-1" + type = "Static" + value = "2" + secret = false + } + + delivery_property { + header_name = "test-dynamic-1" + type = "Dynamic" + source_field = "data.topic" + } + + delivery_property { + header_name = "test-secret-1" + type = "Static" + value = "this-value-is-still-secret!" + secret = true + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} + +func (EventGridEventSubscriptionResource) deliveryPropertiesForEventHubs(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-eg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_eventhub_namespace" "test" { + name = "acctesteventhubnamespace-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku = "Basic" +} + +resource "azurerm_eventhub" "test" { + name = "acctesteventhub-%[1]d" + namespace_name = azurerm_eventhub_namespace.test.name + resource_group_name = azurerm_resource_group.test.name + partition_count = 2 + message_retention = 1 +} + +resource "azurerm_eventgrid_event_subscription" "test" { + name = "acctest-eg-%[1]d" + scope = azurerm_resource_group.test.id + event_delivery_schema = "CloudEventSchemaV1_0" + + eventhub_endpoint_id = azurerm_eventhub.test.id + + delivery_property { + header_name = "test-static-1" + type = "Static" + value = "1" + } +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (EventGridEventSubscriptionResource) deliveryPropertiesForHybridRelay(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-eg-%[1]d" + location = "%[2]s" +} + +resource "azurerm_relay_namespace" "test" { + name = "acctest-%[1]d-rly-eventsub-repo" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku_name = "Standard" +} + +resource "azurerm_relay_hybrid_connection" "test" { + name = "acctest-%[1]d-rhc-eventsub-repo" + resource_group_name = azurerm_resource_group.test.name + relay_namespace_name = azurerm_relay_namespace.test.name + requires_client_authorization = false +} + +resource "azurerm_eventgrid_topic" "test" { + name = "acctest-%[1]d-evg-eventsub-repo" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_eventgrid_event_subscription" "test" { + name = "acctest-eg-%[1]d" + scope = azurerm_eventgrid_topic.test.id + hybrid_connection_endpoint_id = azurerm_relay_hybrid_connection.test.id + + delivery_property { + header_name = "test-static-1" + type = "Static" + value = "1" + } +} +`, data.RandomInteger, data.Locations.Primary) +} diff --git a/website/docs/r/eventgrid_event_subscription.html.markdown b/website/docs/r/eventgrid_event_subscription.html.markdown index a8062fbb13a5..e3003d639cd9 100644 --- a/website/docs/r/eventgrid_event_subscription.html.markdown +++ b/website/docs/r/eventgrid_event_subscription.html.markdown @@ -87,6 +87,8 @@ The following arguments are supported: * `delivery_identity` - (Optional) A `delivery_identity` block as defined below. +* `delivery_property` - (Optional) A `delivery_property` block as defined below. + * `dead_letter_identity` - (Optional) A `dead_letter_identity` block as defined below. -> **Note:** `storage_blob_dead_letter_destination` must be specified when a `dead_letter_identity` is specified @@ -197,6 +199,21 @@ A `delivery_identity` supports the following: * `type` - (Required) Specifies the type of Managed Service Identity that is used for event delivery. Allowed value is `SystemAssigned`. + +--- + +A `delivery_property` supports the following: + +* `header_name` - (Required) The name of the header to send on to the destination + +* `type` - (Required) Either `Static` or `Dynamic` + +* `value` - (Optional) If the `type` is `Static`, then provide the value to use + +* `source_field` - (Optional) If the `type` is `Dynamic`, then provide the payload field to be used as the value. Valid source fields differ by subscription type. + +* `secret` - (Optional) True if the `value` is a secret and should be protected, otherwise false. If True, then this value won't be returned from Azure API calls + --- A `dead_letter_identity` supports the following: