Skip to content

Commit

Permalink
fixed #11623
Browse files Browse the repository at this point in the history
* Support import for custom https configuration

* Update import path

* Update azurerm/internal/services/frontdoor/frontdoor_custom_https_configuration_resource.go

* Add tests, a upgrade guide, and fix validation

* Fix successfully...

* terrafmt guide

* remove frontendId as it's no longer needed

* Update website/docs/guides/2.58.0-frontdoor-upgrade-guide.html.markdown

Co-authored-by: kt <[email protected]>

* Update website/docs/guides/2.58.0-frontdoor-upgrade-guide.html.markdown

Co-authored-by: kt <[email protected]>

* Update website/docs/guides/2.58.0-frontdoor-upgrade-guide.html.markdown

Co-authored-by: kt <[email protected]>

* Update website/docs/guides/2.58.0-frontdoor-upgrade-guide.html.markdown

Co-authored-by: kt <[email protected]>

* Update documentation

Co-authored-by: kt <[email protected]>
  • Loading branch information
WodansSon and katbyte authored May 12, 2021
1 parent ef2b364 commit 2852c72
Show file tree
Hide file tree
Showing 6 changed files with 691 additions and 38 deletions.
63 changes: 44 additions & 19 deletions azurerm/internal/services/frontdoor/customizediff.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,53 +26,78 @@ func customizeHttpsConfigurationCustomizeDiff(ctx context.Context, d *schema.Res
}

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)
return fmt.Errorf(`"custom_https_provisioning_enabled" is set to "false". please remove the "custom_https_configuration" block from the configuration file`)
}

// Verify frontend endpoints custom https configuration is valid if defined
if err := verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig, frontendId); err != nil {
if err := verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig); 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 fmt.Errorf(`"custom_https_provisioning_enabled" is set to "true". please add a "custom_https_configuration" block to the configuration file`)
}

return nil
}

func verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig []interface{}, frontendId string) error {
func verifyCustomHttpsConfiguration(frontendEndpointCustomHttpsConfig []interface{}) 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" and "azure_key_vault_certificate_vault_id"`, frontendId)
certificateSource := customHttpsConfiguration["certificate_source"].(string)
certificateVersion := customHttpsConfiguration["azure_key_vault_certificate_secret_version"].(string)

if certificateSource == string(frontdoor.CertificateSourceFrontDoor) {
if azureKeyVaultCertificateHasValues(customHttpsConfiguration, true) {
return fmt.Errorf(`a Front Door managed "custom_https_configuration" block does not support the following keys. Please remove the following keys from your configuration file: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`)
}
} else {
// The latest secret version is no longer valid for key vaults
if strings.EqualFold(certificateVersion, "latest") {
return fmt.Errorf(`"azure_key_vault_certificate_secret_version" can not be set to "latest" please remove this attribute from the configuration file. Removing the value has the same functionality as setting it to "latest"`)
}

if !azureKeyVaultCertificateHasValues(customHttpsConfiguration, false) {
if certificateVersion == "" {
// If using latest, empty string is now equivalent to using the keyword latest
return fmt.Errorf(`a "AzureKeyVault" managed "custom_https_configuration" block must have values in the following fileds: "azure_key_vault_certificate_secret_name" and "azure_key_vault_certificate_vault_id"`)
} else {
// If using a specific version of the secret
return fmt.Errorf(`a "AzureKeyVault" managed "custom_https_configuration" block must have values in the following fileds: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`)
}
}
} 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"]
func azureKeyVaultCertificateHasValues(customHttpsConfiguration map[string]interface{}, isFrontDoorManaged bool) bool {
certificateSecretName := customHttpsConfiguration["azure_key_vault_certificate_secret_name"].(string)
certificateSecretVersion := customHttpsConfiguration["azure_key_vault_certificate_secret_version"].(string)
certificateVaultId := customHttpsConfiguration["azure_key_vault_certificate_vault_id"].(string)

if matchAllKeys {
if strings.TrimSpace(certificateSecretName.(string)) != "" && strings.TrimSpace(certificateVaultId.(string)) != "" {
if isFrontDoorManaged {
// if any of these keys have values it is invalid
if strings.TrimSpace(certificateSecretName) != "" || strings.TrimSpace(certificateSecretVersion) != "" || strings.TrimSpace(certificateVaultId) != "" {
return true
}
} else if strings.TrimSpace(certificateSecretName.(string)) != "" || strings.TrimSpace(certificateSecretVersion.(string)) != "" || strings.TrimSpace(certificateVaultId.(string)) != "" {
return true
} else {
if certificateSecretVersion == "" {
// using latest ignore certificate secret version
if strings.TrimSpace(certificateSecretName) != "" && strings.TrimSpace(certificateVaultId) != "" {
return true
}
} else {
// not using latest make sure all keys have values
if strings.TrimSpace(certificateSecretName) != "" && strings.TrimSpace(certificateSecretVersion) != "" && strings.TrimSpace(certificateVaultId) != "" {
return true
}
}
}

return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,33 @@ func resourceFrontDoorCustomHttpsConfiguration() *schema.Resource {
Update: resourceFrontDoorCustomHttpsConfigurationCreateUpdate,
Delete: resourceFrontDoorCustomHttpsConfigurationDelete,

Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error {
_, err := parse.FrontendEndpointID(id)
return err
}),
Importer: &schema.ResourceImporter{
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
client := meta.(*clients.Client).Frontdoor.FrontDoorsFrontendClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

// validate that the passed ID is a valid custom HTTPS configuration ID
custom, err := parse.CustomHttpsConfigurationID(d.Id())
if err != nil {
return []*schema.ResourceData{d}, fmt.Errorf("parsing Custom HTTPS Configuration ID %q for import: %v", d.Id(), err)
}

// convert the passed custom HTTPS configuration ID to a frontend endpoint ID
frontend := parse.NewFrontendEndpointID(custom.SubscriptionId, custom.ResourceGroup, custom.FrontDoorName, custom.CustomHttpsConfigurationName)

// validate that the frontend endpoint ID exists in the Frontdoor resource
if _, err = client.Get(ctx, custom.ResourceGroup, custom.FrontDoorName, custom.CustomHttpsConfigurationName); err != nil {
return []*schema.ResourceData{d}, fmt.Errorf("retrieving the Custom HTTPS Configuration(ID: %q) for the frontend endpoint (ID: %q): %s", custom.ID(), frontend.ID(), err)
}

// set the new values for the custom HTTPS configuration resource
d.Set("id", custom.ID())
d.Set("frontend_endpoint_id", frontend.ID())

return []*schema.ResourceData{d}, nil
},
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(6 * time.Hour),
Expand Down Expand Up @@ -82,8 +105,6 @@ func resourceFrontDoorCustomHttpsConfigurationCreateUpdate(d *schema.ResourceDat

customHttpsConfigurationId := parse.NewCustomHttpsConfigurationID(frontendEndpointId.SubscriptionId, frontendEndpointId.ResourceGroup, frontendEndpointId.FrontDoorName, frontendEndpointId.Name)

// TODO: Requires Import support

resp, err := client.Get(ctx, frontendEndpointId.ResourceGroup, frontendEndpointId.FrontDoorName, frontendEndpointId.Name)
if err != nil {
return fmt.Errorf("reading Endpoint %q (Front Door %q / Resource Group %q): %+v", frontendEndpointId.Name, frontendEndpointId.FrontDoorName, frontendEndpointId.ResourceGroup, err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package frontdoor_test
import (
"context"
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
Expand All @@ -22,15 +23,15 @@ func TestAccFrontDoorCustomHttpsConfiguration_CustomHttps(t *testing.T) {
r := FrontDoorCustomHttpsConfigurationResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.CustomHttpsEnabled(data),
Config: r.Enabled(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("custom_https_provisioning_enabled").HasValue("true"),
check.That(data.ResourceName).Key("custom_https_configuration.0.certificate_source").HasValue("FrontDoor"),
),
},
{
Config: r.CustomHttpsDisabled(data),
Config: r.Disabled(data),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("custom_https_provisioning_enabled").HasValue("false"),
Expand All @@ -39,6 +40,72 @@ func TestAccFrontDoorCustomHttpsConfiguration_CustomHttps(t *testing.T) {
})
}

func TestAccFrontDoorCustomHttpsConfiguration_DisabledWithConfigurationBlock(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_frontdoor_custom_https_configuration", "test")
r := FrontDoorCustomHttpsConfigurationResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.DisabledWithConfigurationBlock(data),
ExpectError: regexp.MustCompile(`"custom_https_provisioning_enabled" is set to "false". please remove the "custom_https_configuration" block from the configuration file`),
},
})
}

func TestAccFrontDoorCustomHttpsConfiguration_EnabledWithoutConfigurationBlock(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_frontdoor_custom_https_configuration", "test")
r := FrontDoorCustomHttpsConfigurationResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.EnabledWithoutConfigurationBlock(data),
ExpectError: regexp.MustCompile(`"custom_https_provisioning_enabled" is set to "true". please add a "custom_https_configuration" block to the configuration file`),
},
})
}

func TestAccFrontDoorCustomHttpsConfiguration_EnabledFrontdoorExtraAttributes(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_frontdoor_custom_https_configuration", "test")
r := FrontDoorCustomHttpsConfigurationResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.EnabledFrontdoorExtraAttributes(data),
ExpectError: regexp.MustCompile(`a Front Door managed "custom_https_configuration" block does not support the following keys.`),
},
})
}

func TestAccFrontDoorCustomHttpsConfiguration_EnabledKeyVaultLatest(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_frontdoor_custom_https_configuration", "test")
r := FrontDoorCustomHttpsConfigurationResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.EnabledKeyVaultLatest(data),
ExpectError: regexp.MustCompile(`"azure_key_vault_certificate_secret_version" can not be set to "latest" please remove this attribute from the configuration file.`),
},
})
}

func TestAccFrontDoorCustomHttpsConfiguration_EnabledKeyVaultLatestMissingAttributes(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_frontdoor_custom_https_configuration", "test")
r := FrontDoorCustomHttpsConfigurationResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.EnabledKeyVaultLatestMissingAttributes(data),
ExpectError: regexp.MustCompile(`a "AzureKeyVault" managed "custom_https_configuration" block must have values in the following fileds: "azure_key_vault_certificate_secret_name" and "azure_key_vault_certificate_vault_id"`),
},
})
}

func TestAccFrontDoorCustomHttpsConfiguration_EnabledKeyVaultMissingAttributes(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_frontdoor_custom_https_configuration", "test")
r := FrontDoorCustomHttpsConfigurationResource{}
data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.EnabledKeyVaultMissingAttributes(data),
ExpectError: regexp.MustCompile(`a "AzureKeyVault" managed "custom_https_configuration" block must have values in the following fileds: "azure_key_vault_certificate_secret_name", "azure_key_vault_certificate_secret_version", and "azure_key_vault_certificate_vault_id"`),
},
})
}

func (FrontDoorCustomHttpsConfigurationResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) {
id, err := parse.CustomHttpsConfigurationIDInsensitively(state.ID)
if err != nil {
Expand All @@ -53,7 +120,7 @@ func (FrontDoorCustomHttpsConfigurationResource) Exists(ctx context.Context, cli
return utils.Bool(resp.FrontendEndpointProperties != nil), nil
}

func (r FrontDoorCustomHttpsConfigurationResource) CustomHttpsEnabled(data acceptance.TestData) string {
func (r FrontDoorCustomHttpsConfigurationResource) Enabled(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
Expand All @@ -68,7 +135,7 @@ resource "azurerm_frontdoor_custom_https_configuration" "test" {
`, r.template(data))
}

func (r FrontDoorCustomHttpsConfigurationResource) CustomHttpsDisabled(data acceptance.TestData) string {
func (r FrontDoorCustomHttpsConfigurationResource) Disabled(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
Expand All @@ -79,6 +146,98 @@ resource "azurerm_frontdoor_custom_https_configuration" "test" {
`, r.template(data))
}

func (r FrontDoorCustomHttpsConfigurationResource) DisabledWithConfigurationBlock(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_frontdoor_custom_https_configuration" "test" {
frontend_endpoint_id = azurerm_frontdoor.test.frontend_endpoints[local.endpoint_name]
custom_https_provisioning_enabled = false
custom_https_configuration {
certificate_source = "FrontDoor"
}
}
`, r.template(data))
}

func (r FrontDoorCustomHttpsConfigurationResource) EnabledWithoutConfigurationBlock(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_frontdoor_custom_https_configuration" "test" {
frontend_endpoint_id = azurerm_frontdoor.test.frontend_endpoints[local.endpoint_name]
custom_https_provisioning_enabled = true
}
`, r.template(data))
}

func (r FrontDoorCustomHttpsConfigurationResource) EnabledFrontdoorExtraAttributes(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_frontdoor_custom_https_configuration" "test" {
frontend_endpoint_id = azurerm_frontdoor.test.frontend_endpoints[local.endpoint_name]
custom_https_provisioning_enabled = true
custom_https_configuration {
certificate_source = "FrontDoor"
azure_key_vault_certificate_secret_name = "accTest"
}
}
`, r.template(data))
}

func (r FrontDoorCustomHttpsConfigurationResource) EnabledKeyVaultLatest(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_frontdoor_custom_https_configuration" "test" {
frontend_endpoint_id = azurerm_frontdoor.test.frontend_endpoints[local.endpoint_name]
custom_https_provisioning_enabled = true
custom_https_configuration {
certificate_source = "AzureKeyVault"
azure_key_vault_certificate_secret_name = "accTest"
azure_key_vault_certificate_secret_version = "latest"
}
}
`, r.template(data))
}

func (r FrontDoorCustomHttpsConfigurationResource) EnabledKeyVaultLatestMissingAttributes(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_frontdoor_custom_https_configuration" "test" {
frontend_endpoint_id = azurerm_frontdoor.test.frontend_endpoints[local.endpoint_name]
custom_https_provisioning_enabled = true
custom_https_configuration {
certificate_source = "AzureKeyVault"
azure_key_vault_certificate_secret_name = "accTest"
}
}
`, r.template(data))
}

func (r FrontDoorCustomHttpsConfigurationResource) EnabledKeyVaultMissingAttributes(data acceptance.TestData) string {
return fmt.Sprintf(`
%s
resource "azurerm_frontdoor_custom_https_configuration" "test" {
frontend_endpoint_id = azurerm_frontdoor.test.frontend_endpoints[local.endpoint_name]
custom_https_provisioning_enabled = true
custom_https_configuration {
certificate_source = "AzureKeyVault"
azure_key_vault_certificate_secret_name = "accTest"
azure_key_vault_certificate_secret_version = "accTest"
}
}
`, r.template(data))
}

func (FrontDoorCustomHttpsConfigurationResource) template(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
Loading

0 comments on commit 2852c72

Please sign in to comment.