Skip to content

Commit c1fa839

Browse files
committed
Scaffold Azure RM Route Table resource
1 parent c2d16cd commit c1fa839

6 files changed

Lines changed: 530 additions & 0 deletions

File tree

builtin/providers/azurerm/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ type ArmClient struct {
3737
vnetGatewayConnectionsClient network.VirtualNetworkGatewayConnectionsClient
3838
vnetGatewayClient network.VirtualNetworkGatewaysClient
3939
vnetClient network.VirtualNetworksClient
40+
routeTablesClient network.RouteTablesClient
4041

4142
providers resources.ProvidersClient
4243
resourceGroupClient resources.GroupsClient
@@ -186,6 +187,12 @@ func (c *Config) getArmClient() (*ArmClient, error) {
186187
vnc.Sender = autorest.CreateSender(withRequestLogging())
187188
client.vnetClient = vnc
188189

190+
rtc := network.NewRouteTablesClient(c.SubscriptionID)
191+
setUserAgent(&rtc.Client)
192+
rtc.Authorizer = spt
193+
rtc.Sender = autorest.CreateSender(withRequestLogging())
194+
client.routeTablesClient = rtc
195+
189196
rgc := resources.NewGroupsClient(c.SubscriptionID)
190197
setUserAgent(&rgc.Client)
191198
rgc.Authorizer = spt

builtin/providers/azurerm/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func Provider() terraform.ResourceProvider {
4949
"azurerm_public_ip": resourceArmPublicIp(),
5050
"azurerm_subnet": resourceArmSubnet(),
5151
"azurerm_network_interface": resourceArmNetworkInterface(),
52+
"azurerm_route_table": resourceArmRouteTable(),
5253
},
5354
ConfigureFunc: providerConfigure,
5455
}
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
package azurerm
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"log"
7+
"net/http"
8+
"strings"
9+
"time"
10+
11+
"github.com/Azure/azure-sdk-for-go/arm/network"
12+
"github.com/hashicorp/terraform/helper/hashcode"
13+
"github.com/hashicorp/terraform/helper/resource"
14+
"github.com/hashicorp/terraform/helper/schema"
15+
)
16+
17+
func resourceArmRouteTable() *schema.Resource {
18+
return &schema.Resource{
19+
Create: resourceArmRouteTableCreate,
20+
Read: resourceArmRouteTableRead,
21+
Update: resourceArmRouteTableCreate,
22+
Delete: resourceArmRouteTableDelete,
23+
24+
Schema: map[string]*schema.Schema{
25+
"name": &schema.Schema{
26+
Type: schema.TypeString,
27+
Required: true,
28+
ForceNew: true,
29+
},
30+
31+
"location": &schema.Schema{
32+
Type: schema.TypeString,
33+
Required: true,
34+
ForceNew: true,
35+
StateFunc: azureRMNormalizeLocation,
36+
},
37+
38+
"resource_group_name": &schema.Schema{
39+
Type: schema.TypeString,
40+
Required: true,
41+
ForceNew: true,
42+
},
43+
44+
"route": &schema.Schema{
45+
Type: schema.TypeSet,
46+
Optional: true,
47+
Computed: true,
48+
Elem: &schema.Resource{
49+
Schema: map[string]*schema.Schema{
50+
"name": &schema.Schema{
51+
Type: schema.TypeString,
52+
Required: true,
53+
},
54+
55+
"address_prefix": &schema.Schema{
56+
Type: schema.TypeString,
57+
Required: true,
58+
},
59+
60+
"next_hop_type": &schema.Schema{
61+
Type: schema.TypeString,
62+
Required: true,
63+
ValidateFunc: validateRouteTableNextHopType,
64+
},
65+
66+
"next_hop_in_ip_address": &schema.Schema{
67+
Type: schema.TypeString,
68+
Optional: true,
69+
Computed: true,
70+
},
71+
},
72+
},
73+
Set: resourceArmRouteTableRouteHash,
74+
},
75+
76+
"subnets": &schema.Schema{
77+
Type: schema.TypeSet,
78+
Optional: true,
79+
Computed: true,
80+
Elem: &schema.Schema{Type: schema.TypeString},
81+
Set: schema.HashString,
82+
},
83+
},
84+
}
85+
}
86+
87+
func resourceArmRouteTableCreate(d *schema.ResourceData, meta interface{}) error {
88+
client := meta.(*ArmClient)
89+
routeTablesClient := client.routeTablesClient
90+
91+
log.Printf("[INFO] preparing arguments for Azure ARM Route Table creation.")
92+
93+
name := d.Get("name").(string)
94+
location := d.Get("location").(string)
95+
resGroup := d.Get("resource_group_name").(string)
96+
97+
routeSet := network.RouteTable{
98+
Name: &name,
99+
Location: &location,
100+
}
101+
102+
if _, ok := d.GetOk("route"); ok {
103+
properties := network.RouteTablePropertiesFormat{}
104+
routes, routeErr := expandAzureRmRouteTableRoutes(d)
105+
if routeErr != nil {
106+
return fmt.Errorf("Error Building list of Route Table Routes: %s", routeErr)
107+
}
108+
if len(routes) > 0 {
109+
routeSet.Properties = &properties
110+
}
111+
112+
}
113+
114+
resp, err := routeTablesClient.CreateOrUpdate(resGroup, name, routeSet)
115+
if err != nil {
116+
return err
117+
}
118+
119+
d.SetId(*resp.ID)
120+
121+
log.Printf("[DEBUG] Waiting for Route Table (%s) to become available", name)
122+
stateConf := &resource.StateChangeConf{
123+
Pending: []string{"Accepted", "Updating"},
124+
Target: "Succeeded",
125+
Refresh: routeTableStateRefreshFunc(client, resGroup, name),
126+
Timeout: 10 * time.Minute,
127+
}
128+
if _, err := stateConf.WaitForState(); err != nil {
129+
return fmt.Errorf("Error waiting forRoute Table (%s) to become available: %s", name, err)
130+
}
131+
132+
return resourceArmRouteTableRead(d, meta)
133+
}
134+
135+
func resourceArmRouteTableRead(d *schema.ResourceData, meta interface{}) error {
136+
routeTablesClient := meta.(*ArmClient).routeTablesClient
137+
138+
id, err := parseAzureResourceID(d.Id())
139+
if err != nil {
140+
return err
141+
}
142+
resGroup := id.ResourceGroup
143+
name := id.Path["routeTables"]
144+
145+
resp, err := routeTablesClient.Get(resGroup, name, "")
146+
if resp.StatusCode == http.StatusNotFound {
147+
d.SetId("")
148+
return nil
149+
}
150+
if err != nil {
151+
return fmt.Errorf("Error making Read request on Azure Route Table %s: %s", name, err)
152+
}
153+
154+
if resp.Properties.Subnets != nil {
155+
if len(*resp.Properties.Subnets) > 0 {
156+
subnets := make([]string, 0, len(*resp.Properties.Subnets))
157+
for _, subnet := range *resp.Properties.Subnets {
158+
id := subnet.ID
159+
subnets = append(subnets, *id)
160+
}
161+
162+
if err := d.Set("subnets", subnets); err != nil {
163+
return err
164+
}
165+
}
166+
}
167+
168+
return nil
169+
}
170+
171+
func resourceArmRouteTableDelete(d *schema.ResourceData, meta interface{}) error {
172+
routeTablesClient := meta.(*ArmClient).routeTablesClient
173+
174+
id, err := parseAzureResourceID(d.Id())
175+
if err != nil {
176+
return err
177+
}
178+
resGroup := id.ResourceGroup
179+
name := id.Path["routeTables"]
180+
181+
_, err = routeTablesClient.Delete(resGroup, name)
182+
183+
return err
184+
}
185+
186+
func expandAzureRmRouteTableRoutes(d *schema.ResourceData) ([]network.Route, error) {
187+
configs := d.Get("route").(*schema.Set).List()
188+
routes := make([]network.Route, 0, len(configs))
189+
190+
for _, configRaw := range configs {
191+
data := configRaw.(map[string]interface{})
192+
193+
address_prefix := data["address_prefix"].(string)
194+
next_hop_type := data["next_hop_type"].(string)
195+
196+
properties := network.RoutePropertiesFormat{
197+
AddressPrefix: &address_prefix,
198+
NextHopType: network.RouteNextHopType(next_hop_type),
199+
}
200+
201+
if v := data["next_hop_in_ip_address"].(string); v != "" {
202+
properties.NextHopIPAddress = &v
203+
}
204+
205+
name := data["name"].(string)
206+
route := network.Route{
207+
Name: &name,
208+
Properties: &properties,
209+
}
210+
211+
routes = append(routes, route)
212+
}
213+
214+
return routes, nil
215+
}
216+
217+
func routeTableStateRefreshFunc(client *ArmClient, resourceGroupName string, routeTableName string) resource.StateRefreshFunc {
218+
return func() (interface{}, string, error) {
219+
res, err := client.routeTablesClient.Get(resourceGroupName, routeTableName, "")
220+
if err != nil {
221+
return nil, "", fmt.Errorf("Error issuing read request in routeTableStateRefreshFunc to Azure ARM for route table '%s' (RG: '%s'): %s", routeTableName, resourceGroupName, err)
222+
}
223+
224+
return res, *res.Properties.ProvisioningState, nil
225+
}
226+
}
227+
228+
func resourceArmRouteTableRouteHash(v interface{}) int {
229+
var buf bytes.Buffer
230+
m := v.(map[string]interface{})
231+
buf.WriteString(fmt.Sprintf("%s-", m["name"].(string)))
232+
buf.WriteString(fmt.Sprintf("%s-", m["address_prefix"].(string)))
233+
buf.WriteString(fmt.Sprintf("%s-", m["next_hop_type"].(string)))
234+
235+
return hashcode.String(buf.String())
236+
}
237+
238+
func validateRouteTableNextHopType(v interface{}, k string) (ws []string, errors []error) {
239+
value := strings.ToLower(v.(string))
240+
hopTypes := map[string]bool{
241+
"virtualnetworkgateway": true,
242+
"vnetlocal": true,
243+
"internet": true,
244+
"virtualappliance": true,
245+
"null": true,
246+
}
247+
248+
if !hopTypes[value] {
249+
errors = append(errors, fmt.Errorf("Route Table NextHopType Protocol can only be VirtualNetworkGateway, VnetLocal, Internet or VirtualAppliance"))
250+
}
251+
return
252+
}

0 commit comments

Comments
 (0)