Skip to content

Commit b1c8c30

Browse files
committed
Scaffold the Azure RM Route Resource
1 parent 10a2cbb commit b1c8c30

8 files changed

Lines changed: 387 additions & 2 deletions

File tree

builtin/providers/azurerm/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type ArmClient struct {
3838
vnetGatewayClient network.VirtualNetworkGatewaysClient
3939
vnetClient network.VirtualNetworksClient
4040
routeTablesClient network.RouteTablesClient
41+
routesClient network.RoutesClient
4142

4243
providers resources.ProvidersClient
4344
resourceGroupClient resources.GroupsClient
@@ -193,6 +194,12 @@ func (c *Config) getArmClient() (*ArmClient, error) {
193194
rtc.Sender = autorest.CreateSender(withRequestLogging())
194195
client.routeTablesClient = rtc
195196

197+
rc := network.NewRoutesClient(c.SubscriptionID)
198+
setUserAgent(&rc.Client)
199+
rc.Authorizer = spt
200+
rc.Sender = autorest.CreateSender(withRequestLogging())
201+
client.routesClient = rc
202+
196203
rgc := resources.NewGroupsClient(c.SubscriptionID)
197204
setUserAgent(&rgc.Client)
198205
rgc.Authorizer = spt

builtin/providers/azurerm/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func Provider() terraform.ResourceProvider {
5050
"azurerm_subnet": resourceArmSubnet(),
5151
"azurerm_network_interface": resourceArmNetworkInterface(),
5252
"azurerm_route_table": resourceArmRouteTable(),
53+
"azurerm_route": resourceArmRoute(),
5354
},
5455
ConfigureFunc: providerConfigure,
5556
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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 resourceArmRoute() *schema.Resource {
15+
return &schema.Resource{
16+
Create: resourceArmRouteCreate,
17+
Read: resourceArmRouteRead,
18+
Update: resourceArmRouteCreate,
19+
Delete: resourceArmRouteDelete,
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+
"route_table_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+
"next_hop_type": &schema.Schema{
46+
Type: schema.TypeString,
47+
Required: true,
48+
ValidateFunc: validateRouteTableNextHopType,
49+
},
50+
51+
"next_hop_in_ip_address": &schema.Schema{
52+
Type: schema.TypeString,
53+
Optional: true,
54+
Computed: true,
55+
},
56+
},
57+
}
58+
}
59+
60+
func resourceArmRouteCreate(d *schema.ResourceData, meta interface{}) error {
61+
client := meta.(*ArmClient)
62+
routesClient := client.routesClient
63+
64+
name := d.Get("name").(string)
65+
rtName := d.Get("route_table_name").(string)
66+
resGroup := d.Get("resource_group_name").(string)
67+
68+
addressPrefix := d.Get("address_prefix").(string)
69+
nextHopType := d.Get("next_hop_type").(string)
70+
71+
armMutexKV.Lock(rtName)
72+
defer armMutexKV.Unlock(rtName)
73+
74+
properties := network.RoutePropertiesFormat{
75+
AddressPrefix: &addressPrefix,
76+
NextHopType: network.RouteNextHopType(nextHopType),
77+
}
78+
79+
if v, ok := d.GetOk("next_hop_in_ip_address"); ok {
80+
nextHopInIpAddress := v.(string)
81+
properties.NextHopIPAddress = &nextHopInIpAddress
82+
}
83+
84+
route := network.Route{
85+
Name: &name,
86+
Properties: &properties,
87+
}
88+
89+
resp, err := routesClient.CreateOrUpdate(resGroup, rtName, name, route)
90+
if err != nil {
91+
return err
92+
}
93+
d.SetId(*resp.ID)
94+
95+
log.Printf("[DEBUG] Waiting for Route (%s) to become available", name)
96+
stateConf := &resource.StateChangeConf{
97+
Pending: []string{"Accepted", "Updating"},
98+
Target: "Succeeded",
99+
Refresh: routeStateRefreshFunc(client, resGroup, rtName, name),
100+
Timeout: 10 * time.Minute,
101+
}
102+
if _, err := stateConf.WaitForState(); err != nil {
103+
return fmt.Errorf("Error waiting for Route (%s) to become available: %s", name, err)
104+
}
105+
106+
return resourceArmRouteRead(d, meta)
107+
}
108+
109+
func resourceArmRouteRead(d *schema.ResourceData, meta interface{}) error {
110+
routesClient := meta.(*ArmClient).routesClient
111+
112+
id, err := parseAzureResourceID(d.Id())
113+
if err != nil {
114+
return err
115+
}
116+
resGroup := id.ResourceGroup
117+
rtName := id.Path["routeTables"]
118+
routeName := id.Path["routes"]
119+
120+
resp, err := routesClient.Get(resGroup, rtName, routeName)
121+
if resp.StatusCode == http.StatusNotFound {
122+
d.SetId("")
123+
return nil
124+
}
125+
if err != nil {
126+
return fmt.Errorf("Error making Read request on Azure Route %s: %s", routeName, err)
127+
}
128+
129+
return nil
130+
}
131+
132+
func resourceArmRouteDelete(d *schema.ResourceData, meta interface{}) error {
133+
client := meta.(*ArmClient)
134+
routesClient := client.routesClient
135+
136+
id, err := parseAzureResourceID(d.Id())
137+
if err != nil {
138+
return err
139+
}
140+
resGroup := id.ResourceGroup
141+
rtName := id.Path["routeTables"]
142+
routeName := id.Path["routes"]
143+
144+
armMutexKV.Lock(rtName)
145+
defer armMutexKV.Unlock(rtName)
146+
147+
_, err = routesClient.Delete(resGroup, rtName, routeName)
148+
149+
return err
150+
}
151+
152+
func routeStateRefreshFunc(client *ArmClient, resourceGroupName string, routeTableName string, routeName string) resource.StateRefreshFunc {
153+
return func() (interface{}, string, error) {
154+
res, err := client.routesClient.Get(resourceGroupName, routeTableName, routeName)
155+
if err != nil {
156+
return nil, "", fmt.Errorf("Error issuing read request in routeStateRefreshFunc to Azure ARM for route '%s' (RG: '%s') (NSG: '%s'): %s", routeName, resourceGroupName, routeTableName, err)
157+
}
158+
159+
return res, *res.Properties.ProvisioningState, nil
160+
}
161+
}

builtin/providers/azurerm/resource_arm_route_table.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ func validateRouteTableNextHopType(v interface{}, k string) (ws []string, errors
242242
"vnetlocal": true,
243243
"internet": true,
244244
"virtualappliance": true,
245-
"null": true,
245+
"none": true,
246246
}
247247

248248
if !hopTypes[value] {

builtin/providers/azurerm/resource_arm_route_table_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestResourceAzureRMRouteTableNextHopType_validation(t *testing.T) {
3535
ErrCount: 0,
3636
},
3737
{
38-
Value: "Null",
38+
Value: "None",
3939
ErrCount: 0,
4040
},
4141
{
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
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 TestAccAzureRMRoute_basic(t *testing.T) {
13+
14+
resource.Test(t, resource.TestCase{
15+
PreCheck: func() { testAccPreCheck(t) },
16+
Providers: testAccProviders,
17+
CheckDestroy: testCheckAzureRMRouteDestroy,
18+
Steps: []resource.TestStep{
19+
resource.TestStep{
20+
Config: testAccAzureRMRoute_basic,
21+
Check: resource.ComposeTestCheckFunc(
22+
testCheckAzureRMRouteExists("azurerm_route.test"),
23+
),
24+
},
25+
},
26+
})
27+
}
28+
29+
func TestAccAzureRMRoute_multipleRoutes(t *testing.T) {
30+
31+
resource.Test(t, resource.TestCase{
32+
PreCheck: func() { testAccPreCheck(t) },
33+
Providers: testAccProviders,
34+
CheckDestroy: testCheckAzureRMRouteDestroy,
35+
Steps: []resource.TestStep{
36+
resource.TestStep{
37+
Config: testAccAzureRMRoute_basic,
38+
Check: resource.ComposeTestCheckFunc(
39+
testCheckAzureRMRouteExists("azurerm_route.test"),
40+
),
41+
},
42+
43+
resource.TestStep{
44+
Config: testAccAzureRMRoute_multipleRoutes,
45+
Check: resource.ComposeTestCheckFunc(
46+
testCheckAzureRMRouteExists("azurerm_route.test1"),
47+
),
48+
},
49+
},
50+
})
51+
}
52+
53+
func testCheckAzureRMRouteExists(name string) resource.TestCheckFunc {
54+
return func(s *terraform.State) error {
55+
56+
rs, ok := s.RootModule().Resources[name]
57+
if !ok {
58+
return fmt.Errorf("Not found: %s", name)
59+
}
60+
61+
name := rs.Primary.Attributes["name"]
62+
rtName := rs.Primary.Attributes["route_table_name"]
63+
resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"]
64+
if !hasResourceGroup {
65+
return fmt.Errorf("Bad: no resource group found in state for route: %s", name)
66+
}
67+
68+
conn := testAccProvider.Meta().(*ArmClient).routesClient
69+
70+
resp, err := conn.Get(resourceGroup, rtName, name)
71+
if err != nil {
72+
return fmt.Errorf("Bad: Get on routesClient: %s", err)
73+
}
74+
75+
if resp.StatusCode == http.StatusNotFound {
76+
return fmt.Errorf("Bad: Route %q (resource group: %q) does not exist", name, resourceGroup)
77+
}
78+
79+
return nil
80+
}
81+
}
82+
83+
func testCheckAzureRMRouteDestroy(s *terraform.State) error {
84+
conn := testAccProvider.Meta().(*ArmClient).routesClient
85+
86+
for _, rs := range s.RootModule().Resources {
87+
if rs.Type != "azurerm_route" {
88+
continue
89+
}
90+
91+
name := rs.Primary.Attributes["name"]
92+
rtName := rs.Primary.Attributes["route_table_name"]
93+
resourceGroup := rs.Primary.Attributes["resource_group_name"]
94+
95+
resp, err := conn.Get(resourceGroup, rtName, name)
96+
97+
if err != nil {
98+
return nil
99+
}
100+
101+
if resp.StatusCode != http.StatusNotFound {
102+
return fmt.Errorf("Route still exists:\n%#v", resp.Properties)
103+
}
104+
}
105+
106+
return nil
107+
}
108+
109+
var testAccAzureRMRoute_basic = `
110+
resource "azurerm_resource_group" "test" {
111+
name = "acceptanceTestResourceGroup1"
112+
location = "West US"
113+
}
114+
115+
resource "azurerm_route_table" "test" {
116+
name = "acceptanceTestRouteTable1"
117+
location = "West US"
118+
resource_group_name = "${azurerm_resource_group.test.name}"
119+
}
120+
121+
resource "azurerm_route" "test" {
122+
name = "acceptanceTestRoute1"
123+
resource_group_name = "${azurerm_resource_group.test.name}"
124+
route_table_name = "${azurerm_route_table.test.name}"
125+
126+
address_prefix = "10.1.0.0/16"
127+
next_hop_type = "vnetlocal"
128+
}
129+
`
130+
131+
var testAccAzureRMRoute_multipleRoutes = `
132+
resource "azurerm_resource_group" "test" {
133+
name = "acceptanceTestResourceGroup1"
134+
location = "West US"
135+
}
136+
137+
resource "azurerm_route_table" "test" {
138+
name = "acceptanceTestRouteTable1"
139+
location = "West US"
140+
resource_group_name = "${azurerm_resource_group.test.name}"
141+
}
142+
143+
resource "azurerm_route" "test1" {
144+
name = "acceptanceTestRoute2"
145+
resource_group_name = "${azurerm_resource_group.test.name}"
146+
route_table_name = "${azurerm_route_table.test.name}"
147+
148+
address_prefix = "10.2.0.0/16"
149+
next_hop_type = "none"
150+
}
151+
`

0 commit comments

Comments
 (0)