diff --git a/azurerm/internal/services/apimanagement/api_management_data_source.go b/azurerm/internal/services/apimanagement/api_management_data_source.go index 1cefced64c8e..2bc43c2505b6 100644 --- a/azurerm/internal/services/apimanagement/api_management_data_source.go +++ b/azurerm/internal/services/apimanagement/api_management_data_source.go @@ -37,6 +37,14 @@ func dataSourceApiManagementService() *schema.Resource { }, }, + "private_ip_addresses": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "publisher_name": { Type: schema.TypeString, Computed: true, @@ -134,6 +142,14 @@ func dataSourceApiManagementService() *schema.Resource { Type: schema.TypeString, }, }, + + "private_ip_addresses": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, }, }, }, @@ -224,6 +240,7 @@ func dataSourceApiManagementRead(d *schema.ResourceData, meta interface{}) error d.Set("management_api_url", props.ManagementAPIURL) d.Set("scm_url", props.ScmURL) d.Set("public_ip_addresses", props.PublicIPAddresses) + d.Set("private_ip_addresses", props.PrivateIPAddresses) if err := d.Set("hostname_configuration", flattenDataSourceApiManagementHostnameConfigurations(props.HostnameConfigurations)); err != nil { return fmt.Errorf("setting `hostname_configuration`: %+v", err) @@ -316,6 +333,10 @@ func flattenDataSourceApiManagementAdditionalLocations(input *[]apimanagement.Ad output["public_ip_addresses"] = *prop.PublicIPAddresses } + if prop.PrivateIPAddresses != nil { + output["private_ip_addresses"] = *prop.PrivateIPAddresses + } + if prop.GatewayRegionalURL != nil { output["gateway_regional_url"] = *prop.GatewayRegionalURL } diff --git a/azurerm/internal/services/apimanagement/api_management_resource.go b/azurerm/internal/services/apimanagement/api_management_resource.go index a2027f2e1ea6..8d378a415971 100644 --- a/azurerm/internal/services/apimanagement/api_management_resource.go +++ b/azurerm/internal/services/apimanagement/api_management_resource.go @@ -158,6 +158,22 @@ func resourceArmApiManagementService() *schema.Resource { Schema: map[string]*schema.Schema{ "location": azure.SchemaLocation(), + "virtual_network_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnet_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: azure.ValidateResourceID, + }, + }, + }, + }, + "gateway_regional_url": { Type: schema.TypeString, Computed: true, @@ -170,6 +186,14 @@ func resourceArmApiManagementService() *schema.Resource { }, Computed: true, }, + + "private_ip_addresses": { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, }, }, }, @@ -503,7 +527,11 @@ func resourceArmApiManagementServiceCreateUpdate(d *schema.ResourceData, meta in properties.Identity = identity if _, ok := d.GetOk("additional_location"); ok { - properties.ServiceProperties.AdditionalLocations = expandAzureRmApiManagementAdditionalLocations(d, sku) + var err error + properties.ServiceProperties.AdditionalLocations, err = expandAzureRmApiManagementAdditionalLocations(d, sku) + if err != nil { + return err + } } if notificationSenderEmail != "" { @@ -905,8 +933,9 @@ func expandAzureRmApiManagementCertificates(d *schema.ResourceData) *[]apimanage return &results } -func expandAzureRmApiManagementAdditionalLocations(d *schema.ResourceData, sku *apimanagement.ServiceSkuProperties) *[]apimanagement.AdditionalLocation { +func expandAzureRmApiManagementAdditionalLocations(d *schema.ResourceData, sku *apimanagement.ServiceSkuProperties) (*[]apimanagement.AdditionalLocation, error) { inputLocations := d.Get("additional_location").([]interface{}) + parentVnetConfig := d.Get("virtual_network_configuration").([]interface{}) additionalLocations := make([]apimanagement.AdditionalLocation, 0) @@ -919,10 +948,24 @@ func expandAzureRmApiManagementAdditionalLocations(d *schema.ResourceData, sku * Sku: sku, } + childVnetConfig := config["virtual_network_configuration"].([]interface{}) + switch { + case len(childVnetConfig) == 0 && len(parentVnetConfig) > 0: + return nil, fmt.Errorf("`virtual_network_configuration` must be specified in any `additional_location` block when top-level `virtual_network_configuration` is supplied") + case len(childVnetConfig) > 0 && len(parentVnetConfig) == 0: + return nil, fmt.Errorf("`virtual_network_configuration` must be empty in all `additional_location` blocks when top-level `virtual_network_configuration` is not supplied") + case len(childVnetConfig) > 0 && len(parentVnetConfig) > 0: + v := childVnetConfig[0].(map[string]interface{}) + subnetResourceId := v["subnet_id"].(string) + additionalLocation.VirtualNetworkConfiguration = &apimanagement.VirtualNetworkConfiguration{ + SubnetResourceID: &subnetResourceId, + } + } + additionalLocations = append(additionalLocations, additionalLocation) } - return &additionalLocations + return &additionalLocations, nil } func flattenApiManagementAdditionalLocations(input *[]apimanagement.AdditionalLocation) []interface{} { @@ -942,10 +985,16 @@ func flattenApiManagementAdditionalLocations(input *[]apimanagement.AdditionalLo output["public_ip_addresses"] = *prop.PublicIPAddresses } + if prop.PrivateIPAddresses != nil { + output["private_ip_addresses"] = *prop.PrivateIPAddresses + } + if prop.GatewayRegionalURL != nil { output["gateway_regional_url"] = *prop.GatewayRegionalURL } + output["virtual_network_configuration"] = flattenApiManagementVirtualNetworkConfiguration(prop.VirtualNetworkConfiguration) + results = append(results, output) } diff --git a/azurerm/internal/services/apimanagement/tests/api_management_data_source_test.go b/azurerm/internal/services/apimanagement/tests/api_management_data_source_test.go index 1b2c19a45717..c6c2b106f56b 100644 --- a/azurerm/internal/services/apimanagement/tests/api_management_data_source_test.go +++ b/azurerm/internal/services/apimanagement/tests/api_management_data_source_test.go @@ -29,6 +29,30 @@ func TestAccDataSourceAzureRMApiManagement_basic(t *testing.T) { }) } +func TestAccDataSourceAzureRMApiManagement_virtualNetwork(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_api_management", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceApiManagement_virtualNetwork(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(data.ResourceName, "publisher_email", "pub1@email.com"), + resource.TestCheckResourceAttr(data.ResourceName, "publisher_name", "pub1"), + resource.TestCheckResourceAttr(data.ResourceName, "sku_name", "Premium_1"), + resource.TestCheckResourceAttr(data.ResourceName, "tags.%", "0"), + resource.TestCheckResourceAttrSet(data.ResourceName, "public_ip_addresses.#"), + resource.TestCheckResourceAttrSet(data.ResourceName, "private_ip_addresses.#"), + resource.TestCheckResourceAttrSet(data.ResourceName, "additional_location.0.public_ip_addresses.#"), + resource.TestCheckResourceAttrSet(data.ResourceName, "additional_location.0.private_ip_addresses.#"), + ), + }, + }, + }) +} + func testAccDataSourceApiManagement_basic(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -55,3 +79,76 @@ data "azurerm_api_management" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func testAccDataSourceApiManagement_virtualNetwork(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test1" { + name = "amestRG1-%d" + location = "%s" +} + +resource "azurerm_resource_group" "test2" { + name = "amestRG2-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test1" { + name = "amtestVNET1-%d" + location = azurerm_resource_group.test1.location + resource_group_name = azurerm_resource_group.test1.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_subnet" "test1" { + name = "amtestSNET1-%d" + resource_group_name = azurerm_resource_group.test1.name + virtual_network_name = azurerm_virtual_network.test1.name + address_prefix = "10.0.1.0/24" +} + +resource "azurerm_virtual_network" "test2" { + name = "amtestVNET2-%d" + location = azurerm_resource_group.test2.location + resource_group_name = azurerm_resource_group.test2.name + address_space = ["10.1.0.0/16"] +} + +resource "azurerm_subnet" "test2" { + name = "amtestSNET2-%d" + resource_group_name = azurerm_resource_group.test2.name + virtual_network_name = azurerm_virtual_network.test2.name + address_prefix = "10.1.1.0/24" +} + +resource "azurerm_api_management" "test" { + name = "amtestAM-%d" + location = azurerm_resource_group.test1.location + resource_group_name = azurerm_resource_group.test1.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku_name = "Premium_1" + + additional_location { + location = azurerm_resource_group.test2.location + virtual_network_configuration { + subnet_id = azurerm_subnet.test2.id + } + } + + virtual_network_type = "Internal" + virtual_network_configuration { + subnet_id = azurerm_subnet.test1.id + } +} + +data "azurerm_api_management" "test" { + name = azurerm_api_management.test.name + resource_group_name = azurerm_api_management.test.resource_group_name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.Locations.Secondary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/apimanagement/tests/api_management_resource_test.go b/azurerm/internal/services/apimanagement/tests/api_management_resource_test.go index 5578fac91e65..976e06b4097a 100644 --- a/azurerm/internal/services/apimanagement/tests/api_management_resource_test.go +++ b/azurerm/internal/services/apimanagement/tests/api_management_resource_test.go @@ -175,6 +175,29 @@ func TestAccAzureRMApiManagement_virtualNetworkInternal(t *testing.T) { Check: resource.ComposeTestCheckFunc( testCheckAzureRMApiManagementExists(data.ResourceName), resource.TestCheckResourceAttr(data.ResourceName, "virtual_network_type", "Internal"), + resource.TestCheckResourceAttrSet(data.ResourceName, "private_ip_addresses.#"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMApiManagement_virtualNetworkInternalAdditionalLocation(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMApiManagementDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApiManagement_virtualNetworkInternalAdditionalLocation(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApiManagementExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "virtual_network_type", "Internal"), + resource.TestCheckResourceAttrSet(data.ResourceName, "private_ip_addresses.#"), + resource.TestCheckResourceAttrSet(data.ResourceName, "additional_location.0.private_ip_addresses.#"), ), }, data.ImportStep(), @@ -891,6 +914,74 @@ resource "azurerm_api_management" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } +func testAccAzureRMApiManagement_virtualNetworkInternalAdditionalLocation(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test1" { + name = "acctestRG1-%d" + location = "%s" +} + +resource "azurerm_resource_group" "test2" { + name = "acctestRG2-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test1" { + name = "acctestVNET1-%d" + location = azurerm_resource_group.test1.location + resource_group_name = azurerm_resource_group.test1.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_subnet" "test1" { + name = "acctestSNET1-%d" + resource_group_name = azurerm_resource_group.test1.name + virtual_network_name = azurerm_virtual_network.test1.name + address_prefix = "10.0.1.0/24" +} + +resource "azurerm_virtual_network" "test2" { + name = "acctestVNET2-%d" + location = azurerm_resource_group.test2.location + resource_group_name = azurerm_resource_group.test2.name + address_space = ["10.1.0.0/16"] +} + +resource "azurerm_subnet" "test2" { + name = "acctestSNET2-%d" + resource_group_name = azurerm_resource_group.test2.name + virtual_network_name = azurerm_virtual_network.test2.name + address_prefix = "10.1.1.0/24" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = azurerm_resource_group.test1.location + resource_group_name = azurerm_resource_group.test1.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + + sku_name = "Premium_1" + + additional_location { + location = azurerm_resource_group.test2.location + virtual_network_configuration { + subnet_id = azurerm_subnet.test2.id + } + } + + virtual_network_type = "Internal" + virtual_network_configuration { + subnet_id = azurerm_subnet.test1.id + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.Locations.Secondary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + func testAccAzureRMApiManagement_identityUserAssigned(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/website/docs/d/api_management.html.markdown b/website/docs/d/api_management.html.markdown index cb9f96931352..d51ab695204a 100644 --- a/website/docs/d/api_management.html.markdown +++ b/website/docs/d/api_management.html.markdown @@ -33,7 +33,7 @@ output "api_management_id" { * `id` - The ID of the API Management Service. -* `additional_location` - One or more `additional_location` blocks as defined below +* `additional_location` - Zero or more `additional_location` blocks as defined below * `location` - The Azure location where the API Management Service exists. @@ -55,6 +55,8 @@ output "api_management_id" { * `public_ip_addresses` - The Public IP addresses of the API Management Service. +* `private_ip_addresses` - The Private IP addresses of the API Management Service. + * `publisher_name` - The name of the Publisher/Company of the API Management Service. * `publisher_email` - The email of Publisher/Company of the API Management Service. @@ -75,6 +77,8 @@ A `additional_location` block exports the following: * `public_ip_addresses` - Public Static Load Balanced IP addresses of the API Management service in the additional location. Available only for Basic, Standard and Premium SKU. +* `private_ip_addresses` - Private IP addresses of the API Management service in the additional location, for instances using virtual network mode. + --- A `identity` block exports the following: @@ -164,6 +168,9 @@ A `sku` block exports the following: * `capacity` - Specifies the number of units associated with this API Management service. +--- + + ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: diff --git a/website/docs/r/api_management.html.markdown b/website/docs/r/api_management.html.markdown index 4f11c3a962c5..2325a53afe3f 100644 --- a/website/docs/r/api_management.html.markdown +++ b/website/docs/r/api_management.html.markdown @@ -91,6 +91,8 @@ A `additional_location` block supports the following: * `location` - (Required) The name of the Azure Region in which the API Management Service should be expanded to. +* `virtual_network_configuration` - (Optional) A `virtual_network_configuration` block as defined below. Required when `virtual_network_type` is `External` or `Internal`. + --- A `certificate` block supports the following: @@ -277,7 +279,7 @@ In addition to all arguments above, the following attributes are exported: * `id` - The ID of the API Management Service. -* `additional_location` - One or more `additional_location` blocks as documented below. +* `additional_location` - Zero or more `additional_location` blocks as documented below. * `gateway_url` - The URL of the Gateway for the API Management Service. @@ -293,6 +295,8 @@ In addition to all arguments above, the following attributes are exported: * `public_ip_addresses` - The Public IP addresses of the API Management Service. +* `private_ip_addresses` - The Private IP addresses of the API Management Service. + * `scm_url` - The URL for the SCM (Source Code Management) Endpoint associated with this API Management service. --- @@ -303,6 +307,8 @@ An `additional_location` block exports the following: * `public_ip_addresses` - Public Static Load Balanced IP addresses of the API Management service in the additional location. Available only for Basic, Standard and Premium SKU. +* `private_ip_addresses` - The Private IP addresses of the API Management Service. Available only when the API Manager instance is using Virtual Network mode. + --- An `identity` block exports the following: