2017-01-27 15:32:42 +01:00
|
|
|
package google
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
|
|
"google.golang.org/api/compute/v1"
|
|
|
|
"google.golang.org/api/googleapi"
|
|
|
|
)
|
|
|
|
|
|
|
|
func resourceComputeRouterInterface() *schema.Resource {
|
|
|
|
return &schema.Resource{
|
|
|
|
Create: resourceComputeRouterInterfaceCreate,
|
|
|
|
Read: resourceComputeRouterInterfaceRead,
|
|
|
|
Delete: resourceComputeRouterInterfaceDelete,
|
|
|
|
Importer: &schema.ResourceImporter{
|
|
|
|
State: resourceComputeRouterInterfaceImportState,
|
|
|
|
},
|
|
|
|
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
|
|
"name": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
"router": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
"vpn_tunnel": &schema.Schema{
|
2017-05-19 20:18:23 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
ForceNew: true,
|
|
|
|
DiffSuppressFunc: linkDiffSuppress,
|
2017-01-27 15:32:42 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
"ip_range": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
"project": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
2017-05-19 20:18:23 +02:00
|
|
|
Computed: true,
|
2017-01-27 15:32:42 +01:00
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
|
|
|
|
"region": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceComputeRouterInterfaceCreate(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
|
|
|
|
config := meta.(*Config)
|
|
|
|
|
|
|
|
region, err := getRegion(d, config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
project, err := getProject(d, config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
routerName := d.Get("router").(string)
|
|
|
|
ifaceName := d.Get("name").(string)
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
routerLock := getRouterLockName(region, routerName)
|
|
|
|
mutexKV.Lock(routerLock)
|
|
|
|
defer mutexKV.Unlock(routerLock)
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
routersService := config.clientCompute.Routers
|
2017-01-27 15:32:42 +01:00
|
|
|
router, err := routersService.Get(project, region, routerName).Do()
|
|
|
|
if err != nil {
|
|
|
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf("[WARN] Removing router interface %s because its router %s/%s is gone", ifaceName, region, routerName)
|
2017-01-27 15:32:42 +01:00
|
|
|
d.SetId("")
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
ifaces := router.Interfaces
|
2017-01-27 15:32:42 +01:00
|
|
|
for _, iface := range ifaces {
|
|
|
|
if iface.Name == ifaceName {
|
2017-04-28 21:17:08 +02:00
|
|
|
d.SetId("")
|
|
|
|
return fmt.Errorf("Router %s has interface %s already", routerName, ifaceName)
|
2017-01-27 15:32:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
vpnTunnel, err := getVpnTunnelLink(config, project, region, d.Get("vpn_tunnel").(string))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
iface := &compute.RouterInterface{Name: ifaceName,
|
|
|
|
LinkedVpnTunnel: vpnTunnel}
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
if v, ok := d.GetOk("ip_range"); ok {
|
|
|
|
iface.IpRange = v.(string)
|
|
|
|
}
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf("[INFO] Adding interface %s", ifaceName)
|
|
|
|
ifaces = append(ifaces, iface)
|
|
|
|
patchRouter := &compute.Router{
|
|
|
|
Interfaces: ifaces,
|
|
|
|
}
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf("[DEBUG] Updating router %s/%s with interfaces: %+v", region, routerName, ifaces)
|
|
|
|
op, err := routersService.Patch(project, region, router.Name, patchRouter).Do()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err)
|
|
|
|
}
|
|
|
|
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, ifaceName))
|
|
|
|
err = computeOperationWaitRegion(config, op, project, region, "Patching router")
|
|
|
|
if err != nil {
|
|
|
|
d.SetId("")
|
|
|
|
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
2017-01-27 15:32:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return resourceComputeRouterInterfaceRead(d, meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceComputeRouterInterfaceRead(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
|
|
|
|
config := meta.(*Config)
|
|
|
|
|
|
|
|
region, err := getRegion(d, config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
project, err := getProject(d, config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
routerName := d.Get("router").(string)
|
|
|
|
ifaceName := d.Get("name").(string)
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
routersService := config.clientCompute.Routers
|
2017-01-27 15:32:42 +01:00
|
|
|
router, err := routersService.Get(project, region, routerName).Do()
|
|
|
|
if err != nil {
|
|
|
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf("[WARN] Removing router interface %s because its router %s/%s is gone", ifaceName, region, routerName)
|
2017-01-27 15:32:42 +01:00
|
|
|
d.SetId("")
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
for _, iface := range router.Interfaces {
|
2017-01-27 15:32:42 +01:00
|
|
|
|
|
|
|
if iface.Name == ifaceName {
|
|
|
|
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, ifaceName))
|
2017-05-19 20:18:23 +02:00
|
|
|
d.Set("vpn_tunnel", iface.LinkedVpnTunnel)
|
2017-01-27 15:32:42 +01:00
|
|
|
d.Set("ip_range", iface.IpRange)
|
2017-05-19 20:18:23 +02:00
|
|
|
d.Set("region", region)
|
|
|
|
d.Set("project", project)
|
2017-04-28 21:17:08 +02:00
|
|
|
return nil
|
2017-01-27 15:32:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf("[WARN] Removing router interface %s/%s/%s because it is gone", region, routerName, ifaceName)
|
|
|
|
d.SetId("")
|
2017-01-27 15:32:42 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceComputeRouterInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
|
|
|
|
config := meta.(*Config)
|
|
|
|
|
|
|
|
region, err := getRegion(d, config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
project, err := getProject(d, config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
routerName := d.Get("router").(string)
|
|
|
|
ifaceName := d.Get("name").(string)
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
routerLock := getRouterLockName(region, routerName)
|
|
|
|
mutexKV.Lock(routerLock)
|
|
|
|
defer mutexKV.Unlock(routerLock)
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
routersService := config.clientCompute.Routers
|
2017-01-27 15:32:42 +01:00
|
|
|
router, err := routersService.Get(project, region, routerName).Do()
|
|
|
|
if err != nil {
|
|
|
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf("[WARN] Removing router interface %s because its router %s/%s is gone", ifaceName, region, routerName)
|
2017-01-27 15:32:42 +01:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
var ifaceFound bool
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
newIfaces := make([]*compute.RouterInterface, 0, len(router.Interfaces))
|
|
|
|
for _, iface := range router.Interfaces {
|
2017-01-27 15:32:42 +01:00
|
|
|
|
|
|
|
if iface.Name == ifaceName {
|
|
|
|
ifaceFound = true
|
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
newIfaces = append(newIfaces, iface)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
if !ifaceFound {
|
|
|
|
log.Printf("[DEBUG] Router %s/%s had no interface %s already", region, routerName, ifaceName)
|
|
|
|
d.SetId("")
|
|
|
|
return nil
|
|
|
|
}
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf(
|
|
|
|
"[INFO] Removing interface %s from router %s/%s", ifaceName, region, routerName)
|
|
|
|
patchRouter := &compute.Router{
|
|
|
|
Interfaces: newIfaces,
|
|
|
|
}
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
log.Printf("[DEBUG] Updating router %s/%s with interfaces: %+v", region, routerName, newIfaces)
|
|
|
|
op, err := routersService.Patch(project, region, router.Name, patchRouter).Do()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error patching router %s/%s: %s", region, routerName, err)
|
|
|
|
}
|
2017-01-27 15:32:42 +01:00
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
err = computeOperationWaitRegion(config, op, project, region, "Patching router")
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
2017-01-27 15:32:42 +01:00
|
|
|
}
|
|
|
|
|
2017-04-28 21:17:08 +02:00
|
|
|
d.SetId("")
|
2017-01-27 15:32:42 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceComputeRouterInterfaceImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
|
|
|
parts := strings.Split(d.Id(), "/")
|
|
|
|
if len(parts) != 3 {
|
2017-05-19 20:18:23 +02:00
|
|
|
return nil, fmt.Errorf("Invalid router interface specifier. Expecting {region}/{router}/{interface}")
|
2017-01-27 15:32:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
d.Set("region", parts[0])
|
|
|
|
d.Set("router", parts[1])
|
|
|
|
d.Set("name", parts[2])
|
|
|
|
|
|
|
|
return []*schema.ResourceData{d}, nil
|
|
|
|
}
|