Skip to content

Commit

Permalink
Add azurerm_api_management_custom_domain resource
Browse files Browse the repository at this point in the history
Signed-off-by: Sune Keller <[email protected]>
  • Loading branch information
sirlatrom committed Aug 26, 2020
1 parent 5478538 commit 715556e
Show file tree
Hide file tree
Showing 2 changed files with 314 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
package apimanagement

import (
"fmt"
"log"
"strings"
"time"

"github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2019-12-01/apimanagement"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

var apiManagementCustomDomainResourceName = "azurerm_api_management_custom_domain"

func resourceArmApiManagementCustomDomain() *schema.Resource {
return &schema.Resource{
Create: apiManagementCustomDomainCreateUpdate,
Read: apiManagementCustomDomainRead,
Update: apiManagementCustomDomainCreateUpdate,
Delete: apiManagementCustomDomainDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(30 * time.Minute),
Read: schema.DefaultTimeout(5 * time.Minute),
Update: schema.DefaultTimeout(30 * time.Minute),
Delete: schema.DefaultTimeout(30 * time.Minute),
},

Schema: map[string]*schema.Schema{
"resource_group_name": azure.SchemaResourceGroupName(),

"api_management_name": azure.SchemaApiManagementName(),

"management": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: apiManagementResourceHostnameSchema(),
},
},
"portal": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: apiManagementResourceHostnameSchema(),
},
},
"developer_portal": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: apiManagementResourceHostnameSchema(),
},
},
"proxy": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: apiManagementResourceHostnameProxySchema(),
},
},
"scm": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: apiManagementResourceHostnameSchema(),
},
},
},
}
}

func apiManagementCustomDomainCreateUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).ApiManagement.ServiceClient
ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d)
defer cancel()

log.Printf("[INFO] preparing arguments for API Management Custom domain creation.")

name := d.Get("api_management_name").(string)
resourceGroup := d.Get("resource_group_name").(string)

existing, err := client.Get(ctx, resourceGroup, name)
if err != nil {
return fmt.Errorf("Error finding API Management (API Management %q / Resource Group %q): %s", name, resourceGroup, err)
}

if d.IsNewResource() {
if existing.ServiceProperties.HostnameConfigurations != nil {
return tf.ImportAsExistsError(apiManagementCustomDomainResourceName, *existing.ID)
}
}

existing.ServiceProperties.HostnameConfigurations = expandAzureRmApiManagementHostnameConfigurations(d)

if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, existing); err != nil {
return fmt.Errorf("Error creating/updating Custom Custom domain (API Management %q / Resource Group %q): %+v", name, resourceGroup, err)
}

read, err := client.Get(ctx, resourceGroup, name)
if err != nil {
return fmt.Errorf("Error retrieving Custom Custom domain (API Management %q / Resource Group %q): %+v", name, resourceGroup, err)
}
if read.ID == nil {
return fmt.Errorf("Cannot read Custom domain (API Management %q / Resource Group %q) ID", name, resourceGroup)
}

d.SetId(*read.ID)

return apiManagementCustomDomainRead(d, meta)
}

func apiManagementCustomDomainRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).ApiManagement.ServiceClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}

resourceGroup := id.ResourceGroup
name := id.Path["service"]

resp, err := client.Get(ctx, resourceGroup, name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("API Management Service %q was not found in Resource Group %q - removing from state!", name, resourceGroup)
d.SetId("")
return nil
}

return fmt.Errorf("making Read request on API Management Service %q (Resource Group %q): %+v", name, resourceGroup, err)
}

d.Set("resource_group_name", resourceGroup)
d.Set("api_management_name", resp.Name)

if props := resp.ServiceProperties.HostnameConfigurations; props != nil {
configs := flattenApiManagementHostnameConfiguration(resp.ServiceProperties.HostnameConfigurations, d)
for _, config := range configs {
for key, v := range config.(map[string]interface{}) {
if err := d.Set(key, v); err != nil {
return fmt.Errorf("setting `hostname_configuration` %q: %+v", key, err)
}
}
}
}

return nil
}

func apiManagementCustomDomainDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).ApiManagement.ServiceClient
ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d)
defer cancel()

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}

resourceGroup := id.ResourceGroup
name := id.Path["service"]

resp, err := client.Get(ctx, resourceGroup, name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("API Management Service %q was not found in Resource Group %q - removing from state!", name, resourceGroup)
d.SetId("")
return nil
}

return fmt.Errorf("making Read request on API Management Service %q (Resource Group %q): %+v", name, resourceGroup, err)
}

log.Printf("[DEBUG] Deleting API Management Custom domain (API Management %q / Resource Group %q)", name, resourceGroup)

resp.ServiceProperties.HostnameConfigurations = nil

if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, resp); err != nil {
return fmt.Errorf("Error deleting Custom Custom domain (API Management %q / Resource Group %q): %+v", name, resourceGroup, err)
}

return nil
}

func expandAzureRmApiManagementHostnameConfiguration(d *schema.ResourceData) (apimanagement.HostnameConfiguration, error) {
managementVs := d.Get("management").([]interface{})
for _, managementV := range managementVs {
v := managementV.(map[string]interface{})
return expandApiManagementCommonHostnameConfiguration(v, apimanagement.HostnameTypeManagement), nil
}

portalVs := d.Get("portal").([]interface{})
for _, portalV := range portalVs {
v := portalV.(map[string]interface{})
return expandApiManagementCommonHostnameConfiguration(v, apimanagement.HostnameTypePortal), nil
}

developerPortalVs := d.Get("developer_portal").([]interface{})
for _, developerPortalV := range developerPortalVs {
v := developerPortalV.(map[string]interface{})
return expandApiManagementCommonHostnameConfiguration(v, apimanagement.HostnameTypeDeveloperPortal), nil
}

proxyVs := d.Get("proxy").([]interface{})
for _, proxyV := range proxyVs {
v := proxyV.(map[string]interface{})
output := expandApiManagementCommonHostnameConfiguration(v, apimanagement.HostnameTypeProxy)
if value, ok := v["default_ssl_binding"]; ok {
output.DefaultSslBinding = utils.Bool(value.(bool))
}
return output, nil
}

scmVs := d.Get("scm").([]interface{})
for _, scmV := range scmVs {
v := scmV.(map[string]interface{})
return expandApiManagementCommonHostnameConfiguration(v, apimanagement.HostnameTypeScm), nil
}

return apimanagement.HostnameConfiguration{}, fmt.Errorf("none of the expected hostname configurations found")
}

func flattenApiManagementHostnameConfiguration(input *[]apimanagement.HostnameConfiguration, d *schema.ResourceData) []interface{} {
results := make([]interface{}, 0)
if input == nil {
return results
}

managementResults := make([]interface{}, 0)
portalResults := make([]interface{}, 0)
developerPortalResults := make([]interface{}, 0)
proxyResults := make([]interface{}, 0)
scmResults := make([]interface{}, 0)

for _, config := range *input {
output := make(map[string]interface{})

if config.HostName != nil {
output["host_name"] = *config.HostName
}

if config.NegotiateClientCertificate != nil {
output["negotiate_client_certificate"] = *config.NegotiateClientCertificate
}

if config.KeyVaultID != nil {
output["key_vault_id"] = *config.KeyVaultID
}

// // Iterate through old state to find sensitive props not returned by API.
// // This must be done in order to avoid state diffs.
// // NOTE: this information won't be available during times like Import, so this is a best-effort.
// existingHostnames := d.Get("hostname_configuration").([]interface{})
// if len(existingHostnames) > 0 {
// v := existingHostnames[0].(map[string]interface{})

// if valsRaw, ok := v[strings.ToLower(string(config.Type))]; ok {
// vals := valsRaw.([]interface{})
// for _, val := range vals {
// oldConfig := val.(map[string]interface{})

// if oldConfig["host_name"] == *config.HostName {
// output["certificate_password"] = oldConfig["certificate_password"]
// output["certificate"] = oldConfig["certificate"]
// }
// }
// }
// }

switch strings.ToLower(string(config.Type)) {
case strings.ToLower(string(apimanagement.HostnameTypeProxy)):
// only set SSL binding for proxy types
if config.DefaultSslBinding != nil {
output["default_ssl_binding"] = *config.DefaultSslBinding
}
proxyResults = append(proxyResults, output)

case strings.ToLower(string(apimanagement.HostnameTypeManagement)):
managementResults = append(managementResults, output)

case strings.ToLower(string(apimanagement.HostnameTypePortal)):
portalResults = append(portalResults, output)

case strings.ToLower(string(apimanagement.HostnameTypeDeveloperPortal)):
developerPortalResults = append(developerPortalResults, output)

case strings.ToLower(string(apimanagement.HostnameTypeScm)):
scmResults = append(scmResults, output)
}
}

return []interface{}{
map[string]interface{}{
"management": managementResults,
"portal": portalResults,
"developer_portal": developerPortalResults,
"proxy": proxyResults,
"scm": scmResults,
},
}
}
1 change: 1 addition & 0 deletions azurerm/internal/services/apimanagement/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource {
"azurerm_api_management_authorization_server": resourceArmApiManagementAuthorizationServer(),
"azurerm_api_management_backend": resourceArmApiManagementBackend(),
"azurerm_api_management_certificate": resourceArmApiManagementCertificate(),
"azurerm_api_management_custom_domain": resourceArmApiManagementCustomDomain(),
"azurerm_api_management_diagnostic": resourceArmApiManagementDiagnostic(),
"azurerm_api_management_group": resourceArmApiManagementGroup(),
"azurerm_api_management_group_user": resourceArmApiManagementGroupUser(),
Expand Down

0 comments on commit 715556e

Please sign in to comment.