Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

frontdoor: refactoring & ensuring ID's are consistent #8146

Merged
merged 41 commits into from
Aug 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
1e94b76
internal/resourceid: adding an interface for Resource ID Rewriting
tombuildsstuff Aug 12, 2020
ed3992f
r/frontdoor: adding parsing functions
tombuildsstuff Aug 12, 2020
c1aa996
r/frontdoor: switching the frontendEndpoints to use the custom parsers
tombuildsstuff Aug 12, 2020
536a5ed
r/frontdoor: refactoring the backendpool flatten methods
tombuildsstuff Aug 12, 2020
49ac731
refactor: moving the frontdoor helpers into the frontdoor package
tombuildsstuff Aug 12, 2020
b560532
r/frontdoor: refactoring the backend pool method
tombuildsstuff Aug 12, 2020
dcc75c3
r/frontdoor: removing dead code
tombuildsstuff Aug 12, 2020
f47771d
refactor: ditching the frontdoor prefix
tombuildsstuff Aug 12, 2020
4bbf894
r/frontdoor: refactoring to use the ID parsers/formatters
tombuildsstuff Aug 12, 2020
9008060
r/frontdoor: switching to use the parser method for read/delete
tombuildsstuff Aug 12, 2020
45fdddc
r/frontdoor: fixing an issue where the checkdestroy function was chec…
tombuildsstuff Aug 12, 2020
d707f34
r/frontdoor_firewall_policy: switching to use a consistent id formatter
tombuildsstuff Aug 12, 2020
be9d0e2
refactor: making the helper methods private now this is within the pa…
tombuildsstuff Aug 12, 2020
365663c
firewall: placeholders to check the implementations are valid
tombuildsstuff Aug 12, 2020
2e5a17d
r/frontdoor_custom_https_configuration: fixing the id parsing
tombuildsstuff Aug 13, 2020
6b29cbf
r/frontdoor*: adding import-time validators to check the ID is in the…
tombuildsstuff Aug 13, 2020
6320275
r/frontdoor_firewall_policy: refactoring
tombuildsstuff Aug 13, 2020
0b8a1aa
r/frontdoor_custom_https_configuration: ensuring CU calls Read and de…
tombuildsstuff Aug 13, 2020
56162c3
r/frontdoor_custom_https_configuration: fixing the docs
tombuildsstuff Aug 13, 2020
345952a
r/frontdoor_custom_https_configuration: adding a state migration to p…
tombuildsstuff Aug 13, 2020
8d23d6f
r/frontdoor: fixing a bug in the id formatters
tombuildsstuff Aug 13, 2020
62262eb
r/frontdoor: exposing the correct resource id during a requires impor…
tombuildsstuff Aug 13, 2020
d2d0026
resource-group: deprecated shouldn't be forcenew
tombuildsstuff Aug 13, 2020
6bc28d3
r/frontdoor_firewall_policy: adding a state migration for the ID
tombuildsstuff Aug 13, 2020
a14dfff
r/frontdoor: adding a state migration to fix the I
tombuildsstuff Aug 13, 2020
0176557
WIP
tombuildsstuff Aug 14, 2020
19544cc
r/frontdoor: helps if you set the field
tombuildsstuff Aug 17, 2020
3462bf5
r/frontdoor: renaming the test files to match the resources
tombuildsstuff Aug 17, 2020
59ce804
r/frontdoor_firewall_policy: location is computed
tombuildsstuff Aug 17, 2020
3a7a074
docs: removing conflicting terms
tombuildsstuff Aug 17, 2020
a5c8b47
r/frontdoor_firewall_policy: moving the validation tests over
tombuildsstuff Aug 17, 2020
1c38f16
r/frontdoor: rewriting the ID's to ensure they're consistent
tombuildsstuff Aug 17, 2020
ef7e5ba
frontdoor: tests for the ID Parsers
tombuildsstuff Aug 17, 2020
771075e
r/frontdoor_custom_https_configuration: validating the ID is the corr…
tombuildsstuff Aug 17, 2020
17b4258
r/frontdoor: ensuring the ID is consistent at import time
tombuildsstuff Aug 17, 2020
308f184
typo
tombuildsstuff Aug 17, 2020
33e3b80
r/frontdoor_https_configuration: ensuring the Frontend Endpoint ID is…
tombuildsstuff Aug 17, 2020
8762d5f
frontdoor: moving the customizeDiff out
tombuildsstuff Aug 17, 2020
36c7238
fixing the assertion
tombuildsstuff Aug 17, 2020
2177727
pr comments
tombuildsstuff Aug 18, 2020
75223f4
linting
tombuildsstuff Aug 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 0 additions & 94 deletions azurerm/helpers/azure/frontdoor_custom_https_configuration.go

This file was deleted.

9 changes: 9 additions & 0 deletions azurerm/helpers/azure/resource_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ func SchemaResourceGroupName() *schema.Schema {
}
}

func SchemaResourceGroupNameDeprecated() *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
Optional: true,
ValidateFunc: validateResourceGroupName,
Deprecated: "This field is no longer used and will be removed in the next major version of the Azure Provider",
}
}

func SchemaResourceGroupNameDiffSuppress() *schema.Schema {
return &schema.Schema{
Type: schema.TypeString,
Expand Down
5 changes: 5 additions & 0 deletions azurerm/internal/resourceid/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package resourceid

type Formatter interface {
ID(subscriptionId string) string
}
229 changes: 229 additions & 0 deletions azurerm/internal/services/frontdoor/customizediff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package frontdoor

import (
"fmt"
"strings"

"github.com/Azure/azure-sdk-for-go/services/frontdoor/mgmt/2020-01-01/frontdoor"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/frontdoor/parse"
)

func customizeHttpsConfigurationCustomizeDiff(d *schema.ResourceDiff, v interface{}) error {
if v, ok := d.GetOk("frontend_endpoint_id"); ok && v.(string) != "" {
id, err := parse.FrontendEndpointIDForImport(v.(string))
if err != nil {
return err
}

if err := customHttpsSettings(d); err != nil {
return fmt.Errorf("validating Front Door Custom Https Configuration for Endpoint %q (Front Door %q / Resource Group %q): %+v", id.Name, id.FrontDoorName, id.ResourceGroup, err)
}
}

return nil
}

func customHttpsSettings(d *schema.ResourceDiff) error {
frontendId := d.Get("frontend_endpoint_id").(string)
frontendEndpointCustomHttpsConfig := d.Get("custom_https_configuration").([]interface{})
customHttpsEnabled := d.Get("custom_https_provisioning_enabled").(bool)

if len(frontendEndpointCustomHttpsConfig) > 0 {
if !customHttpsEnabled {
return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid because "custom_https_provisioning_enabled" is set to "false". please remove the "custom_https_configuration" block from the configuration file`, frontendId)
}

// Verify frontend endpoints custom https configuration is valid if defined
if err := verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig, frontendId); err != nil {
return err
}
} else if customHttpsEnabled {
return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid because "custom_https_provisioning_enabled" is set to "true". please add a "custom_https_configuration" block to the configuration file`, frontendId)
}

return nil
}

func verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig []interface{}, frontendId string) error {
if len(frontendEndpointCustomHttpsConfig) > 0 {
customHttpsConfiguration := frontendEndpointCustomHttpsConfig[0].(map[string]interface{})
certificateSource := customHttpsConfiguration["certificate_source"]
if certificateSource == string(frontdoor.CertificateSourceAzureKeyVault) {
if !azureKeyVaultCertificateHasValues(customHttpsConfiguration, true) {
return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid, all of the following keys must have values in the "custom_https_configuration" block: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`, frontendId)
}
} else if azureKeyVaultCertificateHasValues(customHttpsConfiguration, false) {
return fmt.Errorf(`"frontend_endpoint":%q "custom_https_configuration" is invalid, all of the following keys must be removed from the "custom_https_configuration" block: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`, frontendId)
}
}

return nil
}

func azureKeyVaultCertificateHasValues(customHttpsConfiguration map[string]interface{}, matchAllKeys bool) bool {
certificateSecretName := customHttpsConfiguration["azure_key_vault_certificate_secret_name"]
certificateSecretVersion := customHttpsConfiguration["azure_key_vault_certificate_secret_version"]
certificateVaultId := customHttpsConfiguration["azure_key_vault_certificate_vault_id"]

if matchAllKeys {
if strings.TrimSpace(certificateSecretName.(string)) != "" && strings.TrimSpace(certificateSecretVersion.(string)) != "" && strings.TrimSpace(certificateVaultId.(string)) != "" {
return true
}
} else if strings.TrimSpace(certificateSecretName.(string)) != "" || strings.TrimSpace(certificateSecretVersion.(string)) != "" || strings.TrimSpace(certificateVaultId.(string)) != "" {
return true
}

return false
}

func frontDoorCustomizeDiff(d *schema.ResourceDiff, v interface{}) error {
if err := frontDoorSettings(d); err != nil {
return fmt.Errorf("validating Front Door %q (Resource Group %q): %+v", d.Get("name").(string), d.Get("resource_group_name").(string), err)
}

return nil
}

func frontDoorSettings(d *schema.ResourceDiff) error {
routingRules := d.Get("routing_rule").([]interface{})
configFrontendEndpoints := d.Get("frontend_endpoint").([]interface{})
backendPools := d.Get("backend_pool").([]interface{})
loadBalancingSettings := d.Get("backend_pool_load_balancing").([]interface{})
healthProbeSettings := d.Get("backend_pool_health_probe").([]interface{})

if len(configFrontendEndpoints) == 0 {
return fmt.Errorf(`"frontend_endpoint": must have at least one "frontend_endpoint" defined, found 0`)
}

// Loop over all of the Routing Rules and validate that only one type of configuration is defined per Routing Rule
for _, rr := range routingRules {
routingRule := rr.(map[string]interface{})
routingRuleName := routingRule["name"]
redirectConfig := routingRule["redirect_configuration"].([]interface{})
forwardConfig := routingRule["forwarding_configuration"].([]interface{})

// Check 0. validate that at least one routing configuration exists per routing rule
if len(redirectConfig) == 0 && len(forwardConfig) == 0 {
return fmt.Errorf(`routing_rule %s block is invalid. you must have either a "redirect_configuration" or a "forwarding_configuration" defined for the routing_rule %s`, routingRuleName, routingRuleName)
}

// Check 1. validate that only one configuration type is defined per routing rule
if len(redirectConfig) == 1 && len(forwardConfig) == 1 {
return fmt.Errorf(`routing_rule %s block is invalid. "redirect_configuration" conflicts with "forwarding_configuration". You can only have one configuration type per each routing rule`, routingRuleName)
}

// Check 2. routing rule is a forwarding_configuration type make sure the backend_pool_name exists in the configuration file
if len(forwardConfig) > 0 {
fc := forwardConfig[0].(map[string]interface{})

if err := verifyBackendPoolExists(fc["backend_pool_name"].(string), backendPools); err != nil {
return fmt.Errorf(`routing_rule %s is invalid. %+v`, routingRuleName, err)
}
}

// Check 3. validate that each routing rule frontend_endpoints are actually defined in the resource schema
if routingRuleFrontends := routingRule["frontend_endpoints"].([]interface{}); len(routingRuleFrontends) > 0 {
if err := verifyRoutingRuleFrontendEndpoints(routingRuleFrontends, configFrontendEndpoints); err != nil {
return fmt.Errorf(`"routing_rule":%q %+v`, routingRuleName, err)
}
} else {
return fmt.Errorf(`"routing_rule": %q must have at least one "frontend_endpoints" defined`, routingRuleName)
}
}

// Verify backend pool load balancing settings and health probe settings are defined in the resource schema
if err := verifyLoadBalancingAndHealthProbeSettings(backendPools, loadBalancingSettings, healthProbeSettings); err != nil {
return fmt.Errorf(`%+v`, err)
}

return nil
}

func verifyBackendPoolExists(backendPoolName string, backendPools []interface{}) error {
if backendPoolName == "" {
return fmt.Errorf(`"backend_pool_name" cannot be empty`)
}

for _, bps := range backendPools {
backendPool := bps.(map[string]interface{})
if backendPool["name"].(string) == backendPoolName {
return nil
}
}

return fmt.Errorf(`unable to locate "backend_pool_name":%q in configuration file`, backendPoolName)
}

func verifyRoutingRuleFrontendEndpoints(routingRuleFrontends []interface{}, configFrontendEndpoints []interface{}) error {
for _, routingRuleFrontend := range routingRuleFrontends {
// Get the name of the frontend defined in the routing rule
routingRulefrontendName := routingRuleFrontend.(string)
found := false

// Loop over all of the defined frontend endpoints in the config
// seeing if we find the routing rule frontend in the list
for _, configFrontendEndpoint := range configFrontendEndpoints {
configFrontend := configFrontendEndpoint.(map[string]interface{})
configFrontendName := configFrontend["name"]
if routingRulefrontendName == configFrontendName {
found = true
break
}
}

if !found {
return fmt.Errorf(`"frontend_endpoints":%q was not found in the configuration file. verify you have the "frontend_endpoint":%q defined in the configuration file`, routingRulefrontendName, routingRulefrontendName)
}
}

return nil
}

func verifyLoadBalancingAndHealthProbeSettings(backendPools []interface{}, loadBalancingSettings []interface{}, healthProbeSettings []interface{}) error {
for _, bps := range backendPools {
backendPool := bps.(map[string]interface{})
backendPoolName := backendPool["name"]
backendPoolLoadBalancingName := backendPool["load_balancing_name"]
backendPoolHealthProbeName := backendPool["health_probe_name"]
found := false

// Verify backend pool load balancing settings name exists
if len(loadBalancingSettings) > 0 {
for _, lbs := range loadBalancingSettings {
loadBalancing := lbs.(map[string]interface{})
loadBalancingName := loadBalancing["name"]

if loadBalancingName == backendPoolLoadBalancingName {
found = true
break
}
}

if !found {
return fmt.Errorf(`"backend_pool":%q "load_balancing_name":%q was not found in the configuration file. verify you have the "backend_pool_load_balancing":%q defined in the configuration file`, backendPoolName, backendPoolLoadBalancingName, backendPoolLoadBalancingName)
}
}

found = false

// Verify health probe settings name exists
if len(healthProbeSettings) > 0 {
for _, hps := range healthProbeSettings {
healthProbe := hps.(map[string]interface{})
healthProbeName := healthProbe["name"]

if healthProbeName == backendPoolHealthProbeName {
found = true
break
}
}

if !found {
return fmt.Errorf(`"backend_pool":%q "health_probe_name":%q was not found in the configuration file. verify you have the "backend_pool_health_probe":%q defined in the configuration file`, backendPoolName, backendPoolHealthProbeName, backendPoolHealthProbeName)
}
}
}

return nil
}
Loading