-
Notifications
You must be signed in to change notification settings - Fork 9.5k
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
provider/azurerm: add subnet resource #4595
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
package azurerm | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/Azure/azure-sdk-for-go/arm/network" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
) | ||
|
||
func resourceArmSubnet() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceArmSubnetCreate, | ||
Read: resourceArmSubnetRead, | ||
Update: resourceArmSubnetCreate, | ||
Delete: resourceArmSubnetDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"resource_group_name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"virtual_network_name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"address_prefix": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
|
||
"network_security_group_id": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
}, | ||
|
||
"route_table_id": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
}, | ||
|
||
"ip_configurations": &schema.Schema{ | ||
Type: schema.TypeSet, | ||
Optional: true, | ||
Computed: true, | ||
Elem: &schema.Schema{Type: schema.TypeString}, | ||
Set: schema.HashString, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceArmSubnetCreate(d *schema.ResourceData, meta interface{}) error { | ||
client := meta.(*ArmClient) | ||
subnetClient := client.subnetClient | ||
|
||
log.Printf("[INFO] preparing arguments for Azure ARM Subnet creation.") | ||
|
||
name := d.Get("name").(string) | ||
vnetName := d.Get("virtual_network_name").(string) | ||
resGroup := d.Get("resource_group_name").(string) | ||
addressPrefix := d.Get("address_prefix").(string) | ||
|
||
armMutexKV.Lock(vnetName) | ||
defer armMutexKV.Unlock(vnetName) | ||
|
||
properties := network.SubnetPropertiesFormat{ | ||
AddressPrefix: &addressPrefix, | ||
} | ||
|
||
if v, ok := d.GetOk("network_security_group_id"); ok { | ||
nsgId := v.(string) | ||
properties.NetworkSecurityGroup = &network.SecurityGroup{ | ||
ID: &nsgId, | ||
} | ||
} | ||
|
||
if v, ok := d.GetOk("route_table_id"); ok { | ||
rtId := v.(string) | ||
properties.RouteTable = &network.RouteTable{ | ||
ID: &rtId, | ||
} | ||
} | ||
|
||
subnet := network.Subnet{ | ||
Name: &name, | ||
Properties: &properties, | ||
} | ||
|
||
resp, err := subnetClient.CreateOrUpdate(resGroup, vnetName, name, subnet) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(*resp.ID) | ||
|
||
log.Printf("[DEBUG] Waiting for Subnet (%s) to become available", name) | ||
stateConf := &resource.StateChangeConf{ | ||
Pending: []string{"Accepted", "Updating"}, | ||
Target: "Succeeded", | ||
Refresh: subnetRuleStateRefreshFunc(client, resGroup, vnetName, name), | ||
Timeout: 10 * time.Minute, | ||
} | ||
if _, err := stateConf.WaitForState(); err != nil { | ||
return fmt.Errorf("Error waiting for Subnet (%s) to become available: %s", name, err) | ||
} | ||
|
||
return resourceArmSubnetRead(d, meta) | ||
} | ||
|
||
func resourceArmSubnetRead(d *schema.ResourceData, meta interface{}) error { | ||
subnetClient := meta.(*ArmClient).subnetClient | ||
|
||
id, err := parseAzureResourceID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
resGroup := id.ResourceGroup | ||
vnetName := id.Path["virtualNetworks"] | ||
name := id.Path["subnets"] | ||
|
||
resp, err := subnetClient.Get(resGroup, vnetName, name, "") | ||
if resp.StatusCode == http.StatusNotFound { | ||
d.SetId("") | ||
return nil | ||
} | ||
if err != nil { | ||
return fmt.Errorf("Error making Read request on Azure Subnet %s: %s", name, err) | ||
} | ||
|
||
if resp.Properties.IPConfigurations != nil && len(*resp.Properties.IPConfigurations) > 0 { | ||
ips := make([]string, 0, len(*resp.Properties.IPConfigurations)) | ||
for _, ip := range *resp.Properties.IPConfigurations { | ||
ips = append(ips, *ip.ID) | ||
} | ||
|
||
if err := d.Set("ip_configurations", ips); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func resourceArmSubnetDelete(d *schema.ResourceData, meta interface{}) error { | ||
subnetClient := meta.(*ArmClient).subnetClient | ||
|
||
id, err := parseAzureResourceID(d.Id()) | ||
if err != nil { | ||
return err | ||
} | ||
resGroup := id.ResourceGroup | ||
name := id.Path["subnets"] | ||
vnetName := id.Path["virtualNetworks"] | ||
|
||
armMutexKV.Lock(vnetName) | ||
defer armMutexKV.Unlock(vnetName) | ||
|
||
_, err = subnetClient.Delete(resGroup, vnetName, name) | ||
|
||
return err | ||
} | ||
|
||
func subnetRuleStateRefreshFunc(client *ArmClient, resourceGroupName string, virtualNetworkName string, subnetName string) resource.StateRefreshFunc { | ||
return func() (interface{}, string, error) { | ||
res, err := client.subnetClient.Get(resourceGroupName, virtualNetworkName, subnetName, "") | ||
if err != nil { | ||
return nil, "", fmt.Errorf("Error issuing read request in subnetRuleStateRefreshFunc to Azure ARM for subnet '%s' (RG: '%s') (VNN: '%s'): %s", subnetName, resourceGroupName, virtualNetworkName, err) | ||
} | ||
|
||
return res, *res.Properties.ProvisioningState, nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package azurerm | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccAzureRMSubnet_basic(t *testing.T) { | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testCheckAzureRMSubnetDestroy, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ | ||
Config: testAccAzureRMSubnet_basic, | ||
Check: resource.ComposeTestCheckFunc( | ||
testCheckAzureRMSubnetExists("azurerm_subnet.test"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testCheckAzureRMSubnetExists(name string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
// Ensure we have enough information in state to look up in API | ||
rs, ok := s.RootModule().Resources[name] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", name) | ||
} | ||
|
||
name := rs.Primary.Attributes["name"] | ||
vnetName := rs.Primary.Attributes["virtual_network_name"] | ||
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] | ||
if !hasResourceGroup { | ||
return fmt.Errorf("Bad: no resource group found in state for subnet: %s", name) | ||
} | ||
|
||
conn := testAccProvider.Meta().(*ArmClient).subnetClient | ||
|
||
resp, err := conn.Get(resourceGroup, vnetName, name, "") | ||
if err != nil { | ||
return fmt.Errorf("Bad: Get on subnetClient: %s", err) | ||
} | ||
|
||
if resp.StatusCode == http.StatusNotFound { | ||
return fmt.Errorf("Bad: Subnet %q (resource group: %q) does not exist", name, resourceGroup) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testCheckAzureRMSubnetDestroy(s *terraform.State) error { | ||
conn := testAccProvider.Meta().(*ArmClient).subnetClient | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "azurerm_subnet" { | ||
continue | ||
} | ||
|
||
name := rs.Primary.Attributes["name"] | ||
vnetName := rs.Primary.Attributes["virtual_network_name"] | ||
resourceGroup := rs.Primary.Attributes["resource_group_name"] | ||
|
||
resp, err := conn.Get(resourceGroup, vnetName, name, "") | ||
|
||
if err != nil { | ||
return nil | ||
} | ||
|
||
if resp.StatusCode != http.StatusNotFound { | ||
return fmt.Errorf("Subnet still exists:\n%#v", resp.Properties) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
var testAccAzureRMSubnet_basic = ` | ||
resource "azurerm_resource_group" "test" { | ||
name = "acceptanceTestResourceGroup1" | ||
location = "West US" | ||
} | ||
|
||
resource "azurerm_virtual_network" "test" { | ||
name = "acceptanceTestVirtualNetwork1" | ||
address_space = ["10.0.0.0/16"] | ||
location = "West US" | ||
resource_group_name = "${azurerm_resource_group.test.name}" | ||
} | ||
|
||
resource "azurerm_subnet" "test" { | ||
name = "testsubnet" | ||
resource_group_name = "${azurerm_resource_group.test.name}" | ||
virtual_network_name = "${azurerm_virtual_network.test.name}" | ||
address_prefix = "10.0.2.0/24" | ||
} | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
website/source/docs/providers/azurerm/r/subnet.html.markdown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
--- | ||
layout: "azurerm" | ||
page_title: "Azure Resource Manager: azure_subnet" | ||
sidebar_current: "docs-azurerm-resource-subnet" | ||
description: |- | ||
Creates a new subnet. Subnets represent network segments within the IP space defined by the virtual network. | ||
--- | ||
|
||
# azurerm\_subnet | ||
|
||
Creates a new subnet. Subnets represent network segments within the IP space defined by the virtual network. | ||
|
||
## Example Usage | ||
|
||
``` | ||
resource "azurerm_resource_group" "test" { | ||
name = "acceptanceTestResourceGroup1" | ||
location = "West US" | ||
} | ||
|
||
resource "azurerm_virtual_network" "test" { | ||
name = "acceptanceTestVirtualNetwork1" | ||
address_space = ["10.0.0.0/16"] | ||
location = "West US" | ||
resource_group_name = "${azurerm_resource_group.test.name}" | ||
} | ||
|
||
resource "azurerm_subnet" "test" { | ||
name = "testsubnet" | ||
resource_group_name = "${azurerm_resource_group.test.name}" | ||
virtual_network_name = "${azurerm_virtual_network.test.name}" | ||
address_prefix = "10.0.1.0/24" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `name` - (Required) The name of the virtual network. Changing this forces a | ||
new resource to be created. | ||
|
||
* `resource_group_name` - (Required) The name of the resource group in which to | ||
create the subnet. | ||
|
||
* `virtual_network_name` - (Required) The name of the virtual network to which to attach the subnet. | ||
|
||
* `address_prefix` - (Required) The address prefix to use for the subnet. | ||
|
||
* `network_security_group_id` - (Optional) The ID of the Network Security Group to associate with | ||
the subnet. | ||
|
||
* `route_table_id` - (Optional) The ID of the Route Table to associate with | ||
the subnet. | ||
|
||
## Attributes Reference | ||
|
||
The following attributes are exported: | ||
|
||
* `id` - The subnet ID. | ||
* `ip_configurations` - The collection of IP Configurations with IPs within this subnet. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary here to use either all inline subnets or all separate resources? If so we should document this here and in the subnet doc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jen20 this is exactly the same behaviour as for Network Security Group / Network Security Rule
From Slack (with @phinze):