Skip to content

Commit

Permalink
New Resource: azurerm_api_management (#1516)
Browse files Browse the repository at this point in the history
* Azure SDK for API Management added

* Registered API Management Service Client

* Added data source for API Management

* Added azurerm_api_management_service as data source provider

* Added resource for Azure API Management

* Added refs to API Management in sidebar

* Made bash script for creating certs more generic

* Basic integration test for API Management data source

* Documented Azure bug related to destroying azurerm_api_management

* Removed support for Virtual Networks awaiting fix in azure-sdk-for-go. Fixed issues pointed out in review

* removed sku option from additional_location and reuse sku from root

* Removed docs for certificate export, since it was removed

* Updated azure-sdk-for-go and apimanagement with govendor

* * removed sku from additional_location schema
* in-lined sku schema
* do not return error if key is not found in terraform state

* * Set sku to optional and default to Developer
* Removed sku from additional_location schema
* Removed code for flattening sku under additional locations

* Fixing the vendoring

* Fixed issues pointed out in review

* Removed creaded date from docs

* Removed sku from additional_location, since sku will be inherited from root

* Changed config from custom_properties to security with option to disable features, which is the only available custom settings in azure today

* Updated docs for the new security block

* replaced custom_properties section with security section

* Use CofigureClient instead of setting values directly

* changes from review by @katbyte

* refactored and fixed issue related to how custom props are set on API Management Service

* Added apimanagement 2018-06-01-preview using govendor

* Use 2018-06-01-preview of Azure API Management API. Ignore sensitive data not returned from the API during state verification in tests. Fixed other issues pointed out in review.

* Removed old apimanagement package

* Fixed issues related to handling secrets not returned by API

* Added support for Managed Service Identity

* Support ref certs using key_vault_id

* Fixed issue where default ssl binding was set for other hotname types than proxy

* Updated docs for API Management to reflect recent changes. Code cleanup

* Cleaned up data source for api-management

* Fixed API Management example to reflect recent changes

* d/api_management: refactoring

* r/api_management: refactoring to remove the customizeDiff

* Refactoring the API Management Resource:

- refactoring to make the hostname configurations & security block parsing clearer
- default values for the security block
- making name and capacity in the sku block required
- moving the validation test to where the validate function is
- removing crash points & ensuring we set an empty list where required
- registering the `Microsoft.ApiManagement` resource provider

* More refactoring:

- Moving validation into the validation package
- Renaming `hostname_configurations` to `hostname_configuration` to better match the Terraform structure
- Ensuring we always set hostname_configurations
- Setting default values for the `security` block
- Fixing the conflicts_with. rewriting the docs

* Fixing the sidebar highlight

* Fixing the broken tests

* Running tests against different regions to get around the concurrency issues

* Removed duplicate section spacing

* Changed static_ips to public_ip_addresses

* Fixing an incorrect assignment bug

* Updating to v21.1.0 of the Azure SDK

* Resolving PR comments

* Ensuring that different resource groups are provisioned
  • Loading branch information
torresdal authored and tombuildsstuff committed Oct 1, 2018
1 parent 81ab3b8 commit caca04d
Show file tree
Hide file tree
Showing 76 changed files with 39,239 additions and 0 deletions.
11 changes: 11 additions & 0 deletions azurerm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-04-01/network"
"github.com/Azure/azure-sdk-for-go/services/notificationhubs/mgmt/2017-04-01/notificationhubs"
"github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql"
"github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement"
"github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-01-01-preview/authorization"
"github.com/Azure/azure-sdk-for-go/services/preview/dns/mgmt/2018-03-01-preview/dns"
"github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2018-03-01/insights"
Expand Down Expand Up @@ -107,6 +108,9 @@ type ArmClient struct {
redisFirewallClient redis.FirewallRulesClient
redisPatchSchedulesClient redis.PatchSchedulesClient

// API Management
apiManagementServiceClient apimanagement.ServiceClient

// Application Insights
appInsightsClient appinsights.ComponentsClient

Expand Down Expand Up @@ -452,6 +456,7 @@ func getArmClient(c *authentication.Config) (*ArmClient, error) {
return keyVaultSpt, nil
})

client.registerApiManagementServiceClients(endpoint, c.SubscriptionID, auth, sender)
client.registerAppInsightsClients(endpoint, c.SubscriptionID, auth, sender)
client.registerAutomationClients(endpoint, c.SubscriptionID, auth, sender)
client.registerAuthentication(endpoint, graphEndpoint, c.SubscriptionID, c.TenantID, auth, graphAuth, sender)
Expand Down Expand Up @@ -492,6 +497,12 @@ func getArmClient(c *authentication.Config) (*ArmClient, error) {
return &client, nil
}

func (c *ArmClient) registerApiManagementServiceClients(endpoint, subscriptionId string, auth autorest.Authorizer, sender autorest.Sender) {
ams := apimanagement.NewServiceClientWithBaseURI(endpoint, subscriptionId)
c.configureClient(&ams.Client, auth)
c.apiManagementServiceClient = ams
}

func (c *ArmClient) registerAppInsightsClients(endpoint, subscriptionId string, auth autorest.Authorizer, sender autorest.Sender) {
ai := appinsights.NewComponentsClientWithBaseURI(endpoint, subscriptionId)
c.configureClient(&ai.Client, auth)
Expand Down
336 changes: 336 additions & 0 deletions azurerm/data_source_api_management.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
package azurerm

import (
"fmt"
"strings"

"github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement"
"github.com/hashicorp/terraform/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func dataSourceApiManagementService() *schema.Resource {
return &schema.Resource{
Read: dataSourceApiManagementRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validate.ApiManagementServiceName,
},

"resource_group_name": resourceGroupNameForDataSourceSchema(),

"location": locationForDataSourceSchema(),

"publisher_name": {
Type: schema.TypeString,
Computed: true,
},

"publisher_email": {
Type: schema.TypeString,
Computed: true,
},

"sku": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
},
"capacity": {
Type: schema.TypeInt,
Computed: true,
},
},
},
},

"notification_sender_email": {
Type: schema.TypeString,
Computed: true,
},

"gateway_url": {
Type: schema.TypeString,
Computed: true,
},

"gateway_regional_url": {
Type: schema.TypeString,
Computed: true,
},

"portal_url": {
Type: schema.TypeString,
Computed: true,
},

"management_api_url": {
Type: schema.TypeString,
Computed: true,
},

"scm_url": {
Type: schema.TypeString,
Computed: true,
},

"additional_location": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"location": locationForDataSourceSchema(),

"gateway_regional_url": {
Type: schema.TypeString,
Computed: true,
},

"public_ip_addresses": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},

"hostname_configuration": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"management": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: apiManagementDataSourceHostnameSchema(),
},
},
"portal": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: apiManagementDataSourceHostnameSchema(),
},
},
"proxy": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: apiManagementDataSourceHostnameProxySchema(),
},
},
"scm": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: apiManagementDataSourceHostnameSchema(),
},
},
},
},
},

"tags": tagsForDataSourceSchema(),
},
}
}

func dataSourceApiManagementRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).apiManagementServiceClient

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

ctx := meta.(*ArmClient).StopContext
resp, err := client.Get(ctx, resourceGroup, name)

if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("API Management Service %q (Resource Group %q) was not found", name, resourceGroup)
}

return fmt.Errorf("Error retrieving API Management Service %q (Resource Group %q): %+v", name, resourceGroup, err)
}

d.SetId(*resp.ID)

d.Set("name", name)
d.Set("resource_group_name", resourceGroup)

if location := resp.Location; location != nil {
d.Set("location", azureRMNormalizeLocation(*location))
}

if props := resp.ServiceProperties; props != nil {
d.Set("publisher_email", props.PublisherEmail)
d.Set("publisher_name", props.PublisherName)

d.Set("notification_sender_email", props.NotificationSenderEmail)
d.Set("gateway_url", props.GatewayURL)
d.Set("gateway_regional_url", props.GatewayRegionalURL)
d.Set("portal_url", props.PortalURL)
d.Set("management_api_url", props.ManagementAPIURL)
d.Set("scm_url", props.ScmURL)
d.Set("public_ip_addresses", props.PublicIPAddresses)

if err := d.Set("hostname_configuration", flattenDataSourceApiManagementHostnameConfigurations(props.HostnameConfigurations)); err != nil {
return fmt.Errorf("Error setting `hostname_configuration`: %+v", err)
}

if err := d.Set("additional_location", flattenDataSourceApiManagementAdditionalLocations(props.AdditionalLocations)); err != nil {
return fmt.Errorf("Error setting `additional_location`: %+v", err)
}
}

if err := d.Set("sku", flattenDataSourceApiManagementServiceSku(resp.Sku)); err != nil {
return fmt.Errorf("Error flattening `sku`: %+v", err)
}

flattenAndSetTags(d, resp.Tags)

return nil
}

func flattenDataSourceApiManagementHostnameConfigurations(input *[]apimanagement.HostnameConfiguration) []interface{} {
if input == nil {
return []interface{}{}
}

// management, portal, proxy, scm
managementResults := make([]interface{}, 0)
proxyResults := make([]interface{}, 0)
portalResults := make([]interface{}, 0)
scmResults := make([]interface{}, 0)

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

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
}

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

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

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

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

return []interface{}{
map[string]interface{}{
"management": managementResults,
"portal": proxyResults,
"proxy": portalResults,
"scm": scmResults,
},
}
}

func flattenDataSourceApiManagementAdditionalLocations(input *[]apimanagement.AdditionalLocation) []interface{} {
results := make([]interface{}, 0)
if input == nil {
return results
}

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

if prop.Location != nil {
output["location"] = azureRMNormalizeLocation(*prop.Location)
}

if prop.PublicIPAddresses != nil {
output["public_ip_addresses"] = *prop.PublicIPAddresses
}

if prop.GatewayRegionalURL != nil {
output["gateway_regional_url"] = *prop.GatewayRegionalURL
}

results = append(results, output)
}

return results
}

func flattenDataSourceApiManagementServiceSku(profile *apimanagement.ServiceSkuProperties) []interface{} {
if profile == nil {
return []interface{}{}
}

sku := make(map[string]interface{}, 0)

sku["name"] = string(profile.Name)

if profile.Capacity != nil {
sku["capacity"] = *profile.Capacity
}

return []interface{}{sku}
}

func apiManagementDataSourceHostnameSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"host_name": {
Type: schema.TypeString,
Computed: true,
},

"key_vault_id": {
Type: schema.TypeString,
Computed: true,
},

"negotiate_client_certificate": {
Type: schema.TypeBool,
Computed: true,
},
}
}

func apiManagementDataSourceHostnameProxySchema() map[string]*schema.Schema {
hostnameSchema := apiManagementDataSourceHostnameSchema()

hostnameSchema["default_ssl_binding"] = &schema.Schema{
Type: schema.TypeBool,
Computed: true,
}

return hostnameSchema
}
Loading

0 comments on commit caca04d

Please sign in to comment.