Skip to content

Commit 55ba179

Browse files
committed
Scaffold the Azure RM Subnet resource
1 parent a33ffab commit 55ba179

7 files changed

Lines changed: 361 additions & 2 deletions

File tree

builtin/providers/azurerm/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func Provider() terraform.ResourceProvider {
4747
"azurerm_network_security_group": resourceArmNetworkSecurityGroup(),
4848
"azurerm_network_security_rule": resourceArmNetworkSecurityRule(),
4949
"azurerm_public_ip": resourceArmPublicIp(),
50+
"azurerm_subnet": resourceArmSubnet(),
5051
},
5152
ConfigureFunc: providerConfigure,
5253
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package azurerm
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"net/http"
7+
"time"
8+
9+
"github.com/Azure/azure-sdk-for-go/arm/network"
10+
"github.com/hashicorp/terraform/helper/resource"
11+
"github.com/hashicorp/terraform/helper/schema"
12+
)
13+
14+
func resourceArmSubnet() *schema.Resource {
15+
return &schema.Resource{
16+
Create: resourceArmSubnetCreate,
17+
Read: resourceArmSubnetRead,
18+
Update: resourceArmSubnetCreate,
19+
Delete: resourceArmSubnetDelete,
20+
21+
Schema: map[string]*schema.Schema{
22+
"name": &schema.Schema{
23+
Type: schema.TypeString,
24+
Required: true,
25+
ForceNew: true,
26+
},
27+
28+
"resource_group_name": &schema.Schema{
29+
Type: schema.TypeString,
30+
Required: true,
31+
ForceNew: true,
32+
},
33+
34+
"virtual_network_name": &schema.Schema{
35+
Type: schema.TypeString,
36+
Required: true,
37+
ForceNew: true,
38+
},
39+
40+
"address_prefix": &schema.Schema{
41+
Type: schema.TypeString,
42+
Required: true,
43+
},
44+
45+
"network_security_group_id": &schema.Schema{
46+
Type: schema.TypeString,
47+
Optional: true,
48+
Computed: true,
49+
},
50+
51+
"route_table_id": &schema.Schema{
52+
Type: schema.TypeString,
53+
Optional: true,
54+
Computed: true,
55+
},
56+
57+
"ip_configurations": &schema.Schema{
58+
Type: schema.TypeSet,
59+
Optional: true,
60+
Computed: true,
61+
Elem: &schema.Schema{Type: schema.TypeString},
62+
Set: schema.HashString,
63+
},
64+
},
65+
}
66+
}
67+
68+
func resourceArmSubnetCreate(d *schema.ResourceData, meta interface{}) error {
69+
client := meta.(*ArmClient)
70+
subnetClient := client.subnetClient
71+
72+
log.Printf("[INFO] preparing arguments for Azure ARM Subnet creation.")
73+
74+
name := d.Get("name").(string)
75+
vnetName := d.Get("virtual_network_name").(string)
76+
resGroup := d.Get("resource_group_name").(string)
77+
addressPrefix := d.Get("address_prefix").(string)
78+
79+
armMutexKV.Lock(vnetName)
80+
defer armMutexKV.Unlock(vnetName)
81+
82+
properties := network.SubnetPropertiesFormat{
83+
AddressPrefix: &addressPrefix,
84+
}
85+
86+
if v, ok := d.GetOk("network_security_group_id"); ok {
87+
nsgId := v.(string)
88+
properties.NetworkSecurityGroup = &network.SecurityGroup{
89+
ID: &nsgId,
90+
}
91+
}
92+
93+
if v, ok := d.GetOk("route_table_id"); ok {
94+
rtId := v.(string)
95+
properties.RouteTable = &network.RouteTable{
96+
ID: &rtId,
97+
}
98+
}
99+
100+
subnet := network.Subnet{
101+
Name: &name,
102+
Properties: &properties,
103+
}
104+
105+
resp, err := subnetClient.CreateOrUpdate(resGroup, vnetName, name, subnet)
106+
if err != nil {
107+
return err
108+
}
109+
110+
d.SetId(*resp.ID)
111+
112+
log.Printf("[DEBUG] Waiting for Subnet (%s) to become available", name)
113+
stateConf := &resource.StateChangeConf{
114+
Pending: []string{"Accepted", "Updating"},
115+
Target: "Succeeded",
116+
Refresh: subnetRuleStateRefreshFunc(client, resGroup, vnetName, name),
117+
Timeout: 10 * time.Minute,
118+
}
119+
if _, err := stateConf.WaitForState(); err != nil {
120+
return fmt.Errorf("Error waiting for Subnet (%s) to become available: %s", name, err)
121+
}
122+
123+
return resourceArmSubnetRead(d, meta)
124+
}
125+
126+
func resourceArmSubnetRead(d *schema.ResourceData, meta interface{}) error {
127+
subnetClient := meta.(*ArmClient).subnetClient
128+
129+
id, err := parseAzureResourceID(d.Id())
130+
if err != nil {
131+
return err
132+
}
133+
resGroup := id.ResourceGroup
134+
vnetName := id.Path["virtualNetworks"]
135+
name := id.Path["subnets"]
136+
137+
resp, err := subnetClient.Get(resGroup, vnetName, name, "")
138+
if resp.StatusCode == http.StatusNotFound {
139+
d.SetId("")
140+
return nil
141+
}
142+
if err != nil {
143+
return fmt.Errorf("Error making Read request on Azure Subnet %s: %s", name, err)
144+
}
145+
146+
if resp.Properties.IPConfigurations != nil && len(*resp.Properties.IPConfigurations) > 0 {
147+
ips := make([]string, 0, len(*resp.Properties.IPConfigurations))
148+
for _, ip := range *resp.Properties.IPConfigurations {
149+
ips = append(ips, *ip.ID)
150+
}
151+
152+
if err := d.Set("ip_configurations", ips); err != nil {
153+
return err
154+
}
155+
}
156+
157+
return nil
158+
}
159+
160+
func resourceArmSubnetDelete(d *schema.ResourceData, meta interface{}) error {
161+
subnetClient := meta.(*ArmClient).subnetClient
162+
163+
id, err := parseAzureResourceID(d.Id())
164+
if err != nil {
165+
return err
166+
}
167+
resGroup := id.ResourceGroup
168+
name := id.Path["subnets"]
169+
vnetName := id.Path["virtualNetworks"]
170+
171+
armMutexKV.Lock(vnetName)
172+
defer armMutexKV.Unlock(vnetName)
173+
174+
_, err = subnetClient.Delete(resGroup, vnetName, name)
175+
176+
return err
177+
}
178+
179+
func subnetRuleStateRefreshFunc(client *ArmClient, resourceGroupName string, virtualNetworkName string, subnetName string) resource.StateRefreshFunc {
180+
return func() (interface{}, string, error) {
181+
res, err := client.subnetClient.Get(resourceGroupName, virtualNetworkName, subnetName, "")
182+
if err != nil {
183+
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)
184+
}
185+
186+
return res, *res.Properties.ProvisioningState, nil
187+
}
188+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package azurerm
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/hashicorp/terraform/helper/resource"
9+
"github.com/hashicorp/terraform/terraform"
10+
)
11+
12+
func TestAccAzureRMSubnet_basic(t *testing.T) {
13+
14+
resource.Test(t, resource.TestCase{
15+
PreCheck: func() { testAccPreCheck(t) },
16+
Providers: testAccProviders,
17+
CheckDestroy: testCheckAzureRMSubnetDestroy,
18+
Steps: []resource.TestStep{
19+
resource.TestStep{
20+
Config: testAccAzureRMSubnet_basic,
21+
Check: resource.ComposeTestCheckFunc(
22+
testCheckAzureRMSubnetExists("azurerm_subnet.test"),
23+
),
24+
},
25+
},
26+
})
27+
}
28+
29+
func testCheckAzureRMSubnetExists(name string) resource.TestCheckFunc {
30+
return func(s *terraform.State) error {
31+
// Ensure we have enough information in state to look up in API
32+
rs, ok := s.RootModule().Resources[name]
33+
if !ok {
34+
return fmt.Errorf("Not found: %s", name)
35+
}
36+
37+
name := rs.Primary.Attributes["name"]
38+
vnetName := rs.Primary.Attributes["virtual_network_name"]
39+
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"]
40+
if !hasResourceGroup {
41+
return fmt.Errorf("Bad: no resource group found in state for subnet: %s", name)
42+
}
43+
44+
conn := testAccProvider.Meta().(*ArmClient).subnetClient
45+
46+
resp, err := conn.Get(resourceGroup, vnetName, name, "")
47+
if err != nil {
48+
return fmt.Errorf("Bad: Get on subnetClient: %s", err)
49+
}
50+
51+
if resp.StatusCode == http.StatusNotFound {
52+
return fmt.Errorf("Bad: Subnet %q (resource group: %q) does not exist", name, resourceGroup)
53+
}
54+
55+
return nil
56+
}
57+
}
58+
59+
func testCheckAzureRMSubnetDestroy(s *terraform.State) error {
60+
conn := testAccProvider.Meta().(*ArmClient).subnetClient
61+
62+
for _, rs := range s.RootModule().Resources {
63+
if rs.Type != "azurerm_subnet" {
64+
continue
65+
}
66+
67+
name := rs.Primary.Attributes["name"]
68+
vnetName := rs.Primary.Attributes["virtual_network_name"]
69+
resourceGroup := rs.Primary.Attributes["resource_group_name"]
70+
71+
resp, err := conn.Get(resourceGroup, vnetName, name, "")
72+
73+
if err != nil {
74+
return nil
75+
}
76+
77+
if resp.StatusCode != http.StatusNotFound {
78+
return fmt.Errorf("Subnet still exists:\n%#v", resp.Properties)
79+
}
80+
}
81+
82+
return nil
83+
}
84+
85+
var testAccAzureRMSubnet_basic = `
86+
resource "azurerm_resource_group" "test" {
87+
name = "acceptanceTestResourceGroup1"
88+
location = "West US"
89+
}
90+
91+
resource "azurerm_virtual_network" "test" {
92+
name = "acceptanceTestVirtualNetwork1"
93+
address_space = ["10.0.0.0/16"]
94+
location = "West US"
95+
resource_group_name = "${azurerm_resource_group.test.name}"
96+
}
97+
98+
resource "azurerm_subnet" "test" {
99+
name = "testsubnet"
100+
resource_group_name = "${azurerm_resource_group.test.name}"
101+
virtual_network_name = "${azurerm_virtual_network.test.name}"
102+
address_prefix = "10.0.2.0/24"
103+
}
104+
`

builtin/providers/azurerm/resource_arm_virtual_network.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ func resourceArmVirtualNetwork() *schema.Resource {
4242

4343
"subnet": &schema.Schema{
4444
Type: schema.TypeSet,
45-
Required: true,
45+
Optional: true,
46+
Computed: true,
4647
Elem: &schema.Resource{
4748
Schema: map[string]*schema.Schema{
4849
"name": &schema.Schema{
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
layout: "azurerm"
3+
page_title: "Azure Resource Manager: azure_subnet"
4+
sidebar_current: "docs-azurerm-resource-subnet"
5+
description: |-
6+
Creates a new subnet. Subnets represent network segments within the IP space defined by the virtual network.
7+
---
8+
9+
# azurerm\_subnet
10+
11+
Creates a new subnet. Subnets represent network segments within the IP space defined by the virtual network.
12+
13+
## Example Usage
14+
15+
```
16+
resource "azurerm_resource_group" "test" {
17+
name = "acceptanceTestResourceGroup1"
18+
location = "West US"
19+
}
20+
21+
resource "azurerm_virtual_network" "test" {
22+
name = "acceptanceTestVirtualNetwork1"
23+
address_space = ["10.0.0.0/16"]
24+
location = "West US"
25+
resource_group_name = "${azurerm_resource_group.test.name}"
26+
}
27+
28+
resource "azurerm_subnet" "test" {
29+
name = "testsubnet"
30+
resource_group_name = "${azurerm_resource_group.test.name}"
31+
virtual_network_name = "${azurerm_virtual_network.test.name}"
32+
address_prefix = "10.0.1.0/24"
33+
}
34+
```
35+
36+
## Argument Reference
37+
38+
The following arguments are supported:
39+
40+
* `name` - (Required) The name of the virtual network. Changing this forces a
41+
new resource to be created.
42+
43+
* `resource_group_name` - (Required) The name of the resource group in which to
44+
create the subnet.
45+
46+
* `virtual_network_name` - (Required) The name of the virtual network to which to attach the subnet.
47+
48+
* `address_prefix` - (Required) The address prefix to use for the subnet.
49+
50+
* `network_security_group_id` - (Optional) The ID of the Network Security Group to associate with
51+
the subnet.
52+
53+
* `route_table_id` - (Optional) The ID of the Route Table to associate with
54+
the subnet.
55+
56+
## Attributes Reference
57+
58+
The following attributes are exported:
59+
60+
* `id` - The subnet ID.
61+
* `ip_configurations` - The collection of IP Configurations with IPs within this subnet.

website/source/docs/providers/azurerm/r/virtual_network.html.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ The following arguments are supported:
5757
* `dns_servers` - (Optional) List of names of DNS servers previously registered
5858
on Azure.
5959

60-
* `subnet` - (Required) Can be specified multiple times to define multiple
60+
* `subnet` - (Optional) Can be specified multiple times to define multiple
6161
subnets. Each `subnet` block supports fields documented below.
6262

6363
The `subnet` block supports:

website/source/layouts/azurerm.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
<a href="/docs/providers/azurerm/r/public_ip.html">azurerm_public_ip</a>
4242
</li>
4343

44+
<li<%= sidebar_current("docs-azurerm-resource-subnet") %>>
45+
<a href="/docs/providers/azurerm/r/subnet.html">azurerm_subnet</a>
46+
</li>
47+
4448
</ul>
4549
</li>
4650
</ul>

0 commit comments

Comments
 (0)