diff --git a/azurerm/internal/services/network/application_gateway_resource_test.go b/azurerm/internal/services/network/application_gateway_resource_test.go index 04ae3d7363d0..0760f04b919f 100644 --- a/azurerm/internal/services/network/application_gateway_resource_test.go +++ b/azurerm/internal/services/network/application_gateway_resource_test.go @@ -225,6 +225,21 @@ func TestAccApplicationGateway_customHttpListenerFirewallPolicy(t *testing.T) { }) } +func TestAccApplicationGateway_customHttpListenerFirewallPolicyWithAssociations(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_application_gateway", "test") + r := ApplicationGatewayResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.customHttpListenerFirewallPolicyWithAssociations(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + // TODO required soft delete on the keyvault func TestAccApplicationGateway_trustedRootCertificate_keyvault(t *testing.T) { t.Skip() @@ -2085,6 +2100,141 @@ resource "azurerm_application_gateway" "test" { `, r.template(data), data.RandomInteger) } +func (r ApplicationGatewayResource) customHttpListenerFirewallPolicyWithAssociations(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +resource "azurerm_public_ip" "teststd" { + name = "acctest-PubIpStd-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + sku { + name = "WAF_v2" + tier = "WAF_v2" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = azurerm_subnet.test.id + } + + frontend_port { + name = local.frontend_port_name + port = 80 + } + + frontend_ip_configuration { + name = local.frontend_ip_configuration_name + public_ip_address_id = azurerm_public_ip.teststd.id + } + + backend_address_pool { + name = local.backend_address_pool_name + } + + backend_http_settings { + name = local.http_setting_name + cookie_based_affinity = "Disabled" + port = 443 + protocol = "Https" + request_timeout = 1 + + pick_host_name_from_backend_address = true + } + + http_listener { + name = local.listener_name + frontend_ip_configuration_name = local.frontend_ip_configuration_name + frontend_port_name = local.frontend_port_name + protocol = "Http" + firewall_policy_id = azurerm_web_application_firewall_policy.testfwp_listener.id + } + + request_routing_rule { + name = local.request_routing_rule_name + rule_type = "Basic" + http_listener_name = local.listener_name + backend_address_pool_name = local.backend_address_pool_name + backend_http_settings_name = local.http_setting_name + } + + url_path_map { + name = local.url_path_map_name + default_backend_address_pool_name = local.backend_address_pool_name + default_backend_http_settings_name = local.http_setting_name + + path_rule { + name = local.path_rule_name + backend_address_pool_name = local.backend_address_pool_name + backend_http_settings_name = local.http_setting_name + + paths = [ + "/test", + ] + } + } +} + +resource "azurerm_web_application_firewall_policy" "testfwp" { + name = "acctest-fwp-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + + policy_settings { + enabled = true + mode = "Prevention" + } + + managed_rules { + managed_rule_set { + type = "OWASP" + version = "3.1" + } + } +} + +resource "azurerm_web_application_firewall_policy" "testfwp_listener" { + name = "acctest-fwp-listener-%[2]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + http_listener_ids = [for v in azurerm_application_gateway.test.http_listener : v.id] + path_based_rule_ids = flatten([for v in azurerm_application_gateway.test.url_path_map : [for w in v.path_rule : w.id]]) + + policy_settings { + enabled = true + mode = "Prevention" + } + + managed_rules { + managed_rule_set { + type = "OWASP" + version = "3.1" + } + } +} +`, r.template(data), data.RandomInteger) +} + func (r ApplicationGatewayResource) authCertificateUpdated(data acceptance.TestData) string { return fmt.Sprintf(` %[1]s diff --git a/azurerm/internal/services/network/parse/application_gateway_http_listener.go b/azurerm/internal/services/network/parse/application_gateway_http_listener.go new file mode 100644 index 000000000000..79fe3e79f43c --- /dev/null +++ b/azurerm/internal/services/network/parse/application_gateway_http_listener.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type ApplicationGatewayHTTPListenerId struct { + SubscriptionId string + ResourceGroup string + ApplicationGatewayName string + HttpListenerName string +} + +func NewApplicationGatewayHTTPListenerID(subscriptionId, resourceGroup, applicationGatewayName, httpListenerName string) ApplicationGatewayHTTPListenerId { + return ApplicationGatewayHTTPListenerId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ApplicationGatewayName: applicationGatewayName, + HttpListenerName: httpListenerName, + } +} + +func (id ApplicationGatewayHTTPListenerId) String() string { + segments := []string{ + fmt.Sprintf("Http Listener Name %q", id.HttpListenerName), + fmt.Sprintf("Application Gateway Name %q", id.ApplicationGatewayName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Application Gateway H T T P Listener", segmentsStr) +} + +func (id ApplicationGatewayHTTPListenerId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/applicationGateways/%s/httpListeners/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ApplicationGatewayName, id.HttpListenerName) +} + +// ApplicationGatewayHTTPListenerID parses a ApplicationGatewayHTTPListener ID into an ApplicationGatewayHTTPListenerId struct +func ApplicationGatewayHTTPListenerID(input string) (*ApplicationGatewayHTTPListenerId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ApplicationGatewayHTTPListenerId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ApplicationGatewayName, err = id.PopSegment("applicationGateways"); err != nil { + return nil, err + } + if resourceId.HttpListenerName, err = id.PopSegment("httpListeners"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/network/parse/application_gateway_http_listener_test.go b/azurerm/internal/services/network/parse/application_gateway_http_listener_test.go new file mode 100644 index 000000000000..e6f7393a50af --- /dev/null +++ b/azurerm/internal/services/network/parse/application_gateway_http_listener_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = ApplicationGatewayHTTPListenerId{} + +func TestApplicationGatewayHTTPListenerIDFormatter(t *testing.T) { + actual := NewApplicationGatewayHTTPListenerID("12345678-1234-9876-4563-123456789012", "resGroup1", "applicationGateway1", "httpListener1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/httpListeners/httpListener1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestApplicationGatewayHTTPListenerID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ApplicationGatewayHTTPListenerId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Error: true, + }, + + { + // missing value for ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/", + Error: true, + }, + + { + // missing HttpListenerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/", + Error: true, + }, + + { + // missing value for HttpListenerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/httpListeners/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/httpListeners/httpListener1", + Expected: &ApplicationGatewayHTTPListenerId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ApplicationGatewayName: "applicationGateway1", + HttpListenerName: "httpListener1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/APPLICATIONGATEWAYS/APPLICATIONGATEWAY1/HTTPLISTENERS/HTTPLISTENER1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ApplicationGatewayHTTPListenerID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ApplicationGatewayName != v.Expected.ApplicationGatewayName { + t.Fatalf("Expected %q but got %q for ApplicationGatewayName", v.Expected.ApplicationGatewayName, actual.ApplicationGatewayName) + } + if actual.HttpListenerName != v.Expected.HttpListenerName { + t.Fatalf("Expected %q but got %q for HttpListenerName", v.Expected.HttpListenerName, actual.HttpListenerName) + } + } +} diff --git a/azurerm/internal/services/network/parse/application_gateway_url_path_map_path_rule.go b/azurerm/internal/services/network/parse/application_gateway_url_path_map_path_rule.go new file mode 100644 index 000000000000..573434a0d82b --- /dev/null +++ b/azurerm/internal/services/network/parse/application_gateway_url_path_map_path_rule.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type ApplicationGatewayURLPathMapPathRuleId struct { + SubscriptionId string + ResourceGroup string + ApplicationGatewayName string + UrlPathMapName string + PathRuleName string +} + +func NewApplicationGatewayURLPathMapPathRuleID(subscriptionId, resourceGroup, applicationGatewayName, urlPathMapName, pathRuleName string) ApplicationGatewayURLPathMapPathRuleId { + return ApplicationGatewayURLPathMapPathRuleId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ApplicationGatewayName: applicationGatewayName, + UrlPathMapName: urlPathMapName, + PathRuleName: pathRuleName, + } +} + +func (id ApplicationGatewayURLPathMapPathRuleId) String() string { + segments := []string{ + fmt.Sprintf("Path Rule Name %q", id.PathRuleName), + fmt.Sprintf("Url Path Map Name %q", id.UrlPathMapName), + fmt.Sprintf("Application Gateway Name %q", id.ApplicationGatewayName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Application Gateway U R L Path Map Path Rule", segmentsStr) +} + +func (id ApplicationGatewayURLPathMapPathRuleId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/applicationGateways/%s/urlPathMaps/%s/pathRules/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ApplicationGatewayName, id.UrlPathMapName, id.PathRuleName) +} + +// ApplicationGatewayURLPathMapPathRuleID parses a ApplicationGatewayURLPathMapPathRule ID into an ApplicationGatewayURLPathMapPathRuleId struct +func ApplicationGatewayURLPathMapPathRuleID(input string) (*ApplicationGatewayURLPathMapPathRuleId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ApplicationGatewayURLPathMapPathRuleId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.ApplicationGatewayName, err = id.PopSegment("applicationGateways"); err != nil { + return nil, err + } + if resourceId.UrlPathMapName, err = id.PopSegment("urlPathMaps"); err != nil { + return nil, err + } + if resourceId.PathRuleName, err = id.PopSegment("pathRules"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/network/parse/application_gateway_url_path_map_path_rule_test.go b/azurerm/internal/services/network/parse/application_gateway_url_path_map_path_rule_test.go new file mode 100644 index 000000000000..ed1811d287d1 --- /dev/null +++ b/azurerm/internal/services/network/parse/application_gateway_url_path_map_path_rule_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = ApplicationGatewayURLPathMapPathRuleId{} + +func TestApplicationGatewayURLPathMapPathRuleIDFormatter(t *testing.T) { + actual := NewApplicationGatewayURLPathMapPathRuleID("12345678-1234-9876-4563-123456789012", "resGroup1", "applicationGateway1", "urlPathMap1", "pathRule1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/pathRules/pathRule1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestApplicationGatewayURLPathMapPathRuleID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ApplicationGatewayURLPathMapPathRuleId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Error: true, + }, + + { + // missing value for ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/", + Error: true, + }, + + { + // missing UrlPathMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/", + Error: true, + }, + + { + // missing value for UrlPathMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/", + Error: true, + }, + + { + // missing PathRuleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/", + Error: true, + }, + + { + // missing value for PathRuleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/pathRules/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/pathRules/pathRule1", + Expected: &ApplicationGatewayURLPathMapPathRuleId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ApplicationGatewayName: "applicationGateway1", + UrlPathMapName: "urlPathMap1", + PathRuleName: "pathRule1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/APPLICATIONGATEWAYS/APPLICATIONGATEWAY1/URLPATHMAPS/URLPATHMAP1/PATHRULES/PATHRULE1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ApplicationGatewayURLPathMapPathRuleID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.ApplicationGatewayName != v.Expected.ApplicationGatewayName { + t.Fatalf("Expected %q but got %q for ApplicationGatewayName", v.Expected.ApplicationGatewayName, actual.ApplicationGatewayName) + } + if actual.UrlPathMapName != v.Expected.UrlPathMapName { + t.Fatalf("Expected %q but got %q for UrlPathMapName", v.Expected.UrlPathMapName, actual.UrlPathMapName) + } + if actual.PathRuleName != v.Expected.PathRuleName { + t.Fatalf("Expected %q but got %q for PathRuleName", v.Expected.PathRuleName, actual.PathRuleName) + } + } +} diff --git a/azurerm/internal/services/network/resourceids.go b/azurerm/internal/services/network/resourceids.go index 965dc1514633..c21a23e73a5e 100644 --- a/azurerm/internal/services/network/resourceids.go +++ b/azurerm/internal/services/network/resourceids.go @@ -2,6 +2,8 @@ package network // Core bits and pieces //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ApplicationGateway -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ApplicationGatewayHTTPListener -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/httpListeners/httpListener1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ApplicationGatewayURLPathMapPathRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/pathRules/pathRule1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=IpGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/ipGroups/group1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=NetworkInterface -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/networkInterfaces/networkInterface1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=NetworkSecurityGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/networkSecurityGroups/securityGroup1 diff --git a/azurerm/internal/services/network/validate/application_gateway_http_listener_id.go b/azurerm/internal/services/network/validate/application_gateway_http_listener_id.go new file mode 100644 index 000000000000..270d28281f77 --- /dev/null +++ b/azurerm/internal/services/network/validate/application_gateway_http_listener_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +func ApplicationGatewayHTTPListenerID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ApplicationGatewayHTTPListenerID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/network/validate/application_gateway_http_listener_id_test.go b/azurerm/internal/services/network/validate/application_gateway_http_listener_id_test.go new file mode 100644 index 000000000000..5f219ca8cc09 --- /dev/null +++ b/azurerm/internal/services/network/validate/application_gateway_http_listener_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestApplicationGatewayHTTPListenerID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Valid: false, + }, + + { + // missing value for ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/", + Valid: false, + }, + + { + // missing HttpListenerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/", + Valid: false, + }, + + { + // missing value for HttpListenerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/httpListeners/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/httpListeners/httpListener1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/APPLICATIONGATEWAYS/APPLICATIONGATEWAY1/HTTPLISTENERS/HTTPLISTENER1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ApplicationGatewayHTTPListenerID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/network/validate/application_gateway_url_path_map_path_rule_id.go b/azurerm/internal/services/network/validate/application_gateway_url_path_map_path_rule_id.go new file mode 100644 index 000000000000..629db131be9c --- /dev/null +++ b/azurerm/internal/services/network/validate/application_gateway_url_path_map_path_rule_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +func ApplicationGatewayURLPathMapPathRuleID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ApplicationGatewayURLPathMapPathRuleID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/network/validate/application_gateway_url_path_map_path_rule_id_test.go b/azurerm/internal/services/network/validate/application_gateway_url_path_map_path_rule_id_test.go new file mode 100644 index 000000000000..49f428bc635b --- /dev/null +++ b/azurerm/internal/services/network/validate/application_gateway_url_path_map_path_rule_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestApplicationGatewayURLPathMapPathRuleID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/", + Valid: false, + }, + + { + // missing value for ApplicationGatewayName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/", + Valid: false, + }, + + { + // missing UrlPathMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/", + Valid: false, + }, + + { + // missing value for UrlPathMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/", + Valid: false, + }, + + { + // missing PathRuleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/", + Valid: false, + }, + + { + // missing value for PathRuleName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/pathRules/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Network/applicationGateways/applicationGateway1/urlPathMaps/urlPathMap1/pathRules/pathRule1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.NETWORK/APPLICATIONGATEWAYS/APPLICATIONGATEWAY1/URLPATHMAPS/URLPATHMAP1/PATHRULES/PATHRULE1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ApplicationGatewayURLPathMapPathRuleID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/network/validate/web_application_firewall_policy.go b/azurerm/internal/services/network/validate/web_application_firewall_policy.go index 5dcbf69af587..cf83b5fbaa8d 100644 --- a/azurerm/internal/services/network/validate/web_application_firewall_policy.go +++ b/azurerm/internal/services/network/validate/web_application_firewall_policy.go @@ -1,6 +1,8 @@ package validate -import "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) var ValidateWebApplicationFirewallPolicyRuleGroupName = validation.StringInSlice([]string{ "crs_20_protocol_violations", diff --git a/azurerm/internal/services/network/web_application_firewall_policy_resource.go b/azurerm/internal/services/network/web_application_firewall_policy_resource.go index 3f497614bfca..a354756efe7d 100644 --- a/azurerm/internal/services/network/web_application_firewall_policy_resource.go +++ b/azurerm/internal/services/network/web_application_firewall_policy_resource.go @@ -282,6 +282,26 @@ func resourceWebApplicationFirewallPolicy() *schema.Resource { }, }, + "http_listener_ids": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validate.ApplicationGatewayHTTPListenerID, + }, + }, + + "path_based_rule_ids": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validate.ApplicationGatewayURLPathMapPathRuleID, + }, + }, + "tags": tags.Schema(), }, } @@ -310,6 +330,8 @@ func resourceWebApplicationFirewallPolicyCreateUpdate(d *schema.ResourceData, me location := azure.NormalizeLocation(d.Get("location").(string)) customRules := d.Get("custom_rules").([]interface{}) policySettings := d.Get("policy_settings").([]interface{}) + httpListenerIDs := d.Get("http_listener_ids").([]interface{}) + pathBasedRuleIDs := d.Get("path_based_rule_ids").([]interface{}) managedRules := d.Get("managed_rules").([]interface{}) t := d.Get("tags").(map[string]interface{}) @@ -319,6 +341,8 @@ func resourceWebApplicationFirewallPolicyCreateUpdate(d *schema.ResourceData, me CustomRules: expandWebApplicationFirewallPolicyWebApplicationFirewallCustomRule(customRules), PolicySettings: expandWebApplicationFirewallPolicyPolicySettings(policySettings), ManagedRules: expandWebApplicationFirewallPolicyManagedRulesDefinition(managedRules), + HTTPListeners: expandIDsToSubResources(httpListenerIDs), + PathBasedRules: expandIDsToSubResources(pathBasedRuleIDs), }, Tags: tags.Expand(t), } @@ -376,8 +400,11 @@ func resourceWebApplicationFirewallPolicyRead(d *schema.ResourceData, meta inter if err := d.Set("managed_rules", flattenWebApplicationFirewallPolicyManagedRulesDefinition(webApplicationFirewallPolicyPropertiesFormat.ManagedRules)); err != nil { return fmt.Errorf("Error setting `managed_rules`: %+v", err) } - if err := d.Set("managed_rules", flattenWebApplicationFirewallPolicyManagedRulesDefinition(webApplicationFirewallPolicyPropertiesFormat.ManagedRules)); err != nil { - return fmt.Errorf("Error setting `managed_rules`: %+v", err) + if err := d.Set("http_listener_ids", flattenSubResourcesToIDs(webApplicationFirewallPolicyPropertiesFormat.HTTPListeners)); err != nil { + return fmt.Errorf("Error setting `http_listeners`: %+v", err) + } + if err := d.Set("path_based_rule_ids", flattenSubResourcesToIDs(webApplicationFirewallPolicyPropertiesFormat.PathBasedRules)); err != nil { + return fmt.Errorf("Error setting `path_based_rules`: %+v", err) } } diff --git a/website/docs/r/web_application_firewall_policy.html.markdown b/website/docs/r/web_application_firewall_policy.html.markdown index 3f2d48e42b18..3b3bfff486eb 100644 --- a/website/docs/r/web_application_firewall_policy.html.markdown +++ b/website/docs/r/web_application_firewall_policy.html.markdown @@ -122,6 +122,10 @@ The following arguments are supported: * `managed_rules` - (Required) A `managed_rules` blocks as defined below. +* `http_listener_ids` - (Optional) A list of HTTP Listener IDs from an `azurerm_application_gateway`. + +* `path_based_rule_ids` - (Optional) A list of URL Path Map Path Rule IDs from an `azurerm_application_gateway`. + * `tags` - (Optional) A mapping of tags to assign to the Web Application Firewall Policy. ---