mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-04 17:51:11 +00:00
c605b0bc4b
<!-- This change is generated by MagicModules. --> /cc @rileykarson
388 lines
11 KiB
Go
388 lines
11 KiB
Go
package google
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"strings"
|
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
"github.com/hashicorp/terraform/helper/validation"
|
|
computeBeta "google.golang.org/api/compute/v0.beta"
|
|
|
|
"google.golang.org/api/googleapi"
|
|
)
|
|
|
|
var (
|
|
routerNatSubnetworkConfig = &schema.Resource{
|
|
Schema: map[string]*schema.Schema{
|
|
"name": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
"source_ip_ranges_to_nat": {
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
"secondary_ip_range_names": {
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
},
|
|
}
|
|
)
|
|
|
|
func resourceComputeRouterNat() *schema.Resource {
|
|
return &schema.Resource{
|
|
// TODO(https://github.com/GoogleCloudPlatform/magic-modules/issues/963): Implement Update
|
|
Create: resourceComputeRouterNatCreate,
|
|
Read: resourceComputeRouterNatRead,
|
|
Delete: resourceComputeRouterNatDelete,
|
|
Importer: &schema.ResourceImporter{
|
|
State: resourceComputeRouterNatImportState,
|
|
},
|
|
|
|
Timeouts: &schema.ResourceTimeout{
|
|
Create: schema.DefaultTimeout(10 * time.Minute),
|
|
Delete: schema.DefaultTimeout(10 * time.Minute),
|
|
},
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
"name": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
ValidateFunc: validateRFC1035Name(2, 63),
|
|
},
|
|
"router": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
},
|
|
"nat_ip_allocate_option": {
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
ValidateFunc: validation.StringInSlice([]string{"MANUAL_ONLY", "AUTO_ONLY"}, false),
|
|
},
|
|
"nat_ips": {
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
"source_subnetwork_ip_ranges_to_nat": {
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
ValidateFunc: validation.StringInSlice([]string{"ALL_SUBNETWORKS_ALL_IP_RANGES", "ALL_SUBNETWORKS_ALL_PRIMARY_IP_RANGES", "LIST_OF_SUBNETWORKS"}, false),
|
|
},
|
|
"subnetwork": {
|
|
Type: schema.TypeSet,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Elem: routerNatSubnetworkConfig,
|
|
},
|
|
"min_ports_per_vm": {
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"udp_idle_timeout_sec": {
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"icmp_idle_timeout_sec": {
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"tcp_established_idle_timeout_sec": {
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"tcp_transitory_idle_timeout_sec": {
|
|
Type: schema.TypeInt,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
"project": {
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
Computed: true,
|
|
ForceNew: true,
|
|
},
|
|
"region": {
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
Computed: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func resourceComputeRouterNatCreate(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)
|
|
natName := d.Get("name").(string)
|
|
|
|
routerLock := getRouterLockName(region, routerName)
|
|
mutexKV.Lock(routerLock)
|
|
defer mutexKV.Unlock(routerLock)
|
|
|
|
routersService := config.clientComputeBeta.Routers
|
|
router, err := routersService.Get(project, region, routerName).Do()
|
|
if err != nil {
|
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
|
return fmt.Errorf("Router %s/%s not found", region, routerName)
|
|
}
|
|
|
|
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
|
}
|
|
|
|
nats := router.Nats
|
|
for _, nat := range nats {
|
|
if nat.Name == natName {
|
|
return fmt.Errorf("Router %s has nat %s already", routerName, natName)
|
|
}
|
|
}
|
|
|
|
nat := &computeBeta.RouterNat{
|
|
Name: natName,
|
|
NatIpAllocateOption: d.Get("nat_ip_allocate_option").(string),
|
|
NatIps: convertStringArr(d.Get("nat_ips").(*schema.Set).List()),
|
|
SourceSubnetworkIpRangesToNat: d.Get("source_subnetwork_ip_ranges_to_nat").(string),
|
|
MinPortsPerVm: int64(d.Get("min_ports_per_vm").(int)),
|
|
UdpIdleTimeoutSec: int64(d.Get("udp_idle_timeout_sec").(int)),
|
|
IcmpIdleTimeoutSec: int64(d.Get("icmp_idle_timeout_sec").(int)),
|
|
TcpEstablishedIdleTimeoutSec: int64(d.Get("tcp_established_idle_timeout_sec").(int)),
|
|
TcpTransitoryIdleTimeoutSec: int64(d.Get("tcp_transitory_idle_timeout_sec").(int)),
|
|
}
|
|
|
|
if v, ok := d.GetOk("subnetwork"); ok {
|
|
nat.Subnetworks = expandSubnetworks(v.(*schema.Set).List())
|
|
}
|
|
|
|
log.Printf("[INFO] Adding nat %s", natName)
|
|
nats = append(nats, nat)
|
|
patchRouter := &computeBeta.Router{
|
|
Nats: nats,
|
|
}
|
|
|
|
log.Printf("[DEBUG] Updating router %s/%s with nats: %+v", region, routerName, nats)
|
|
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, natName))
|
|
err = computeBetaOperationWaitTime(config.clientCompute, op, project, "Patching router", int(d.Timeout(schema.TimeoutCreate).Minutes()))
|
|
if err != nil {
|
|
d.SetId("")
|
|
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
|
}
|
|
|
|
return resourceComputeRouterNatRead(d, meta)
|
|
}
|
|
|
|
func resourceComputeRouterNatRead(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)
|
|
natName := d.Get("name").(string)
|
|
|
|
routersService := config.clientComputeBeta.Routers
|
|
router, err := routersService.Get(project, region, routerName).Do()
|
|
if err != nil {
|
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
|
log.Printf("[WARN] Removing router nat %s because its router %s/%s is gone", natName, region, routerName)
|
|
d.SetId("")
|
|
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("Error Reading router %s/%s: %s", region, routerName, err)
|
|
}
|
|
|
|
for _, nat := range router.Nats {
|
|
|
|
if nat.Name == natName {
|
|
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, natName))
|
|
d.Set("nat_ip_allocate_option", nat.NatIpAllocateOption)
|
|
d.Set("nat_ips", schema.NewSet(schema.HashString, convertStringArrToInterface(convertSelfLinksToV1(nat.NatIps))))
|
|
d.Set("source_subnetwork_ip_ranges_to_nat", nat.SourceSubnetworkIpRangesToNat)
|
|
d.Set("min_ports_per_vm", nat.MinPortsPerVm)
|
|
d.Set("udp_idle_timeout_sec", nat.UdpIdleTimeoutSec)
|
|
d.Set("icmp_idle_timeout_sec", nat.IcmpIdleTimeoutSec)
|
|
d.Set("tcp_established_idle_timeout_sec", nat.TcpEstablishedIdleTimeoutSec)
|
|
d.Set("tcp_transitory_idle_timeout_sec", nat.TcpTransitoryIdleTimeoutSec)
|
|
d.Set("region", region)
|
|
d.Set("project", project)
|
|
|
|
if err := d.Set("subnetwork", flattenRouterNatSubnetworkToNatBeta(nat.Subnetworks)); err != nil {
|
|
return fmt.Errorf("Error reading router nat: %s", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
log.Printf("[WARN] Removing router nat %s/%s/%s because it is gone", region, routerName, natName)
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
|
|
func resourceComputeRouterNatDelete(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)
|
|
natName := d.Get("name").(string)
|
|
|
|
routerLock := getRouterLockName(region, routerName)
|
|
mutexKV.Lock(routerLock)
|
|
defer mutexKV.Unlock(routerLock)
|
|
|
|
routersService := config.clientComputeBeta.Routers
|
|
router, err := routersService.Get(project, region, routerName).Do()
|
|
if err != nil {
|
|
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
|
log.Printf("[WARN] Removing router nat %s because its router %s/%s is gone", natName, region, routerName)
|
|
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("Error Reading Router %s: %s", routerName, err)
|
|
}
|
|
|
|
var newNats []*computeBeta.RouterNat = make([]*computeBeta.RouterNat, 0, len(router.Nats))
|
|
for _, nat := range router.Nats {
|
|
if nat.Name == natName {
|
|
continue
|
|
} else {
|
|
newNats = append(newNats, nat)
|
|
}
|
|
}
|
|
|
|
if len(newNats) == len(router.Nats) {
|
|
log.Printf("[DEBUG] Router %s/%s had no nat %s already", region, routerName, natName)
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
|
|
log.Printf("[INFO] Removing nat %s from router %s/%s", natName, region, routerName)
|
|
patchRouter := &computeBeta.Router{
|
|
Nats: newNats,
|
|
}
|
|
|
|
if len(newNats) == 0 {
|
|
patchRouter.ForceSendFields = append(patchRouter.ForceSendFields, "Nats")
|
|
}
|
|
|
|
log.Printf("[DEBUG] Updating router %s/%s with nats: %+v", region, routerName, newNats)
|
|
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)
|
|
}
|
|
|
|
err = computeBetaOperationWaitTime(config.clientCompute, op, project, "Patching router", int(d.Timeout(schema.TimeoutDelete).Minutes()))
|
|
if err != nil {
|
|
return fmt.Errorf("Error waiting to patch router %s/%s: %s", region, routerName, err)
|
|
}
|
|
|
|
d.SetId("")
|
|
return nil
|
|
}
|
|
|
|
func resourceComputeRouterNatImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
|
|
parts := strings.Split(d.Id(), "/")
|
|
if len(parts) != 3 {
|
|
return nil, fmt.Errorf("Invalid router nat specifier. Expecting {region}/{router}/{nat}")
|
|
}
|
|
|
|
d.Set("region", parts[0])
|
|
d.Set("router", parts[1])
|
|
d.Set("name", parts[2])
|
|
|
|
return []*schema.ResourceData{d}, nil
|
|
}
|
|
|
|
func expandSubnetworks(subnetworks []interface{}) []*computeBeta.RouterNatSubnetworkToNat {
|
|
result := make([]*computeBeta.RouterNatSubnetworkToNat, 0, len(subnetworks))
|
|
|
|
for _, subnetwork := range subnetworks {
|
|
snm := subnetwork.(map[string]interface{})
|
|
subnetworkToNat := computeBeta.RouterNatSubnetworkToNat{
|
|
Name: snm["name"].(string),
|
|
SourceIpRangesToNat: convertStringSet(snm["source_ip_ranges_to_nat"].(*schema.Set)),
|
|
}
|
|
if v, ok := snm["secondary_ip_range_names"]; ok {
|
|
subnetworkToNat.SecondaryIpRangeNames = convertStringSet(v.(*schema.Set))
|
|
}
|
|
result = append(result, &subnetworkToNat)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func flattenRouterNatSubnetworkToNatBeta(subnetworksToNat []*computeBeta.RouterNatSubnetworkToNat) []map[string]interface{} {
|
|
result := make([]map[string]interface{}, 0, len(subnetworksToNat))
|
|
for _, subnetworkToNat := range subnetworksToNat {
|
|
stnMap := make(map[string]interface{})
|
|
stnMap["name"] = ConvertSelfLinkToV1(subnetworkToNat.Name)
|
|
stnMap["source_ip_ranges_to_nat"] = schema.NewSet(schema.HashString, convertStringArrToInterface(subnetworkToNat.SourceIpRangesToNat))
|
|
stnMap["secondary_ip_range_names"] = schema.NewSet(schema.HashString, convertStringArrToInterface(subnetworkToNat.SecondaryIpRangeNames))
|
|
result = append(result, stnMap)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func convertSelfLinksToV1(selfLinks []string) []string {
|
|
result := make([]string, 0, len(selfLinks))
|
|
for _, selfLink := range selfLinks {
|
|
result = append(result, ConvertSelfLinkToV1(selfLink))
|
|
}
|
|
return result
|
|
}
|