provider/google: Support Import of 'google_compute_firewall'
This commit is contained in:
parent
782b24833a
commit
09df0efd1c
|
@ -0,0 +1,32 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccComputeFirewall_importBasic(t *testing.T) {
|
||||||
|
resourceName := "google_compute_firewall.foobar"
|
||||||
|
networkName := fmt.Sprintf("firewall-test-%s", acctest.RandString(10))
|
||||||
|
firewallName := fmt.Sprintf("firewall-test-%s", acctest.RandString(10))
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckComputeFirewallDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccComputeFirewall_basic(networkName, firewallName),
|
||||||
|
},
|
||||||
|
|
||||||
|
resource.TestStep{
|
||||||
|
ResourceName: resourceName,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/helper/hashcode"
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
@ -18,6 +19,10 @@ func resourceComputeFirewall() *schema.Resource {
|
||||||
Read: resourceComputeFirewallRead,
|
Read: resourceComputeFirewallRead,
|
||||||
Update: resourceComputeFirewallUpdate,
|
Update: resourceComputeFirewallUpdate,
|
||||||
Delete: resourceComputeFirewallDelete,
|
Delete: resourceComputeFirewallDelete,
|
||||||
|
Importer: &schema.ResourceImporter{
|
||||||
|
State: schema.ImportStatePassthrough,
|
||||||
|
},
|
||||||
|
SchemaVersion: 1,
|
||||||
|
|
||||||
Schema: map[string]*schema.Schema{
|
Schema: map[string]*schema.Schema{
|
||||||
"name": &schema.Schema{
|
"name": &schema.Schema{
|
||||||
|
@ -43,10 +48,9 @@ func resourceComputeFirewall() *schema.Resource {
|
||||||
},
|
},
|
||||||
|
|
||||||
"ports": &schema.Schema{
|
"ports": &schema.Schema{
|
||||||
Type: schema.TypeSet,
|
Type: schema.TypeList,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Elem: &schema.Schema{Type: schema.TypeString},
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
Set: schema.HashString,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -62,6 +66,7 @@ func resourceComputeFirewall() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
|
Computed: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
"self_link": &schema.Schema{
|
"self_link": &schema.Schema{
|
||||||
|
@ -101,11 +106,7 @@ func resourceComputeFirewallAllowHash(v interface{}) int {
|
||||||
// We need to make sure to sort the strings below so that we always
|
// We need to make sure to sort the strings below so that we always
|
||||||
// generate the same hash code no matter what is in the set.
|
// generate the same hash code no matter what is in the set.
|
||||||
if v, ok := m["ports"]; ok {
|
if v, ok := m["ports"]; ok {
|
||||||
vs := v.(*schema.Set).List()
|
s := convertStringArr(v.([]interface{}))
|
||||||
s := make([]string, len(vs))
|
|
||||||
for i, raw := range vs {
|
|
||||||
s[i] = raw.(string)
|
|
||||||
}
|
|
||||||
sort.Strings(s)
|
sort.Strings(s)
|
||||||
|
|
||||||
for _, v := range s {
|
for _, v := range s {
|
||||||
|
@ -146,6 +147,18 @@ func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) err
|
||||||
return resourceComputeFirewallRead(d, meta)
|
return resourceComputeFirewallRead(d, meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func flattenAllowed(allowed []*compute.FirewallAllowed) []map[string]interface{} {
|
||||||
|
result := make([]map[string]interface{}, 0, len(allowed))
|
||||||
|
for _, allow := range allowed {
|
||||||
|
allowMap := make(map[string]interface{})
|
||||||
|
allowMap["protocol"] = allow.IPProtocol
|
||||||
|
allowMap["ports"] = allow.Ports
|
||||||
|
|
||||||
|
result = append(result, allowMap)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
|
func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
config := meta.(*Config)
|
config := meta.(*Config)
|
||||||
|
|
||||||
|
@ -168,8 +181,16 @@ func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error
|
||||||
return fmt.Errorf("Error reading firewall: %s", err)
|
return fmt.Errorf("Error reading firewall: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
networkUrl := strings.Split(firewall.Network, "/")
|
||||||
d.Set("self_link", firewall.SelfLink)
|
d.Set("self_link", firewall.SelfLink)
|
||||||
|
d.Set("name", firewall.Name)
|
||||||
|
d.Set("network", networkUrl[len(networkUrl)-1])
|
||||||
|
d.Set("description", firewall.Description)
|
||||||
|
d.Set("project", project)
|
||||||
|
d.Set("source_ranges", firewall.SourceRanges)
|
||||||
|
d.Set("source_tags", firewall.SourceTags)
|
||||||
|
d.Set("target_tags", firewall.TargetTags)
|
||||||
|
d.Set("allow", flattenAllowed(firewall.Allowed))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,10 +271,10 @@ func resourceFirewall(
|
||||||
m := v.(map[string]interface{})
|
m := v.(map[string]interface{})
|
||||||
|
|
||||||
var ports []string
|
var ports []string
|
||||||
if v := m["ports"].(*schema.Set); v.Len() > 0 {
|
if v := convertStringArr(m["ports"].([]interface{})); len(v) > 0 {
|
||||||
ports = make([]string, v.Len())
|
ports = make([]string, len(v))
|
||||||
for i, v := range v.List() {
|
for i, v := range v {
|
||||||
ports[i] = v.(string)
|
ports[i] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceComputeFirewallMigrateState(
|
||||||
|
v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
|
||||||
|
if is.Empty() {
|
||||||
|
log.Println("[DEBUG] Empty FirewallState; nothing to migrate.")
|
||||||
|
return is, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v {
|
||||||
|
case 0:
|
||||||
|
log.Println("[INFO] Found Compute Firewall State v0; migrating to v1")
|
||||||
|
is, err := migrateFirewallStateV0toV1(is)
|
||||||
|
if err != nil {
|
||||||
|
return is, err
|
||||||
|
}
|
||||||
|
return is, nil
|
||||||
|
default:
|
||||||
|
return is, fmt.Errorf("Unexpected schema version: %d", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func migrateFirewallStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
|
||||||
|
log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)
|
||||||
|
idx := 0
|
||||||
|
portCount := 0
|
||||||
|
newPorts := make(map[string]string)
|
||||||
|
keys := make([]string, len(is.Attributes))
|
||||||
|
for k, _ := range is.Attributes {
|
||||||
|
keys[idx] = k
|
||||||
|
idx++
|
||||||
|
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
if !strings.HasPrefix(k, "allow.") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if k == "allow.#" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(k, ".ports.#") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(k, ".protocol") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have a key that looks like "allow.<hash>.ports.*" and we know it's not
|
||||||
|
// allow.<hash>.ports.# because we deleted it above, so it must be allow.<hash1>.ports.<hash2>
|
||||||
|
// from the Set of Ports. Just need to convert it to a list by
|
||||||
|
// replacing second hash with sequential numbers.
|
||||||
|
kParts := strings.Split(k, ".")
|
||||||
|
|
||||||
|
// Sanity check: all four parts should be there and <hash> should be a number
|
||||||
|
badFormat := false
|
||||||
|
if len(kParts) != 4 {
|
||||||
|
badFormat = true
|
||||||
|
} else if _, err := strconv.Atoi(kParts[1]); err != nil {
|
||||||
|
badFormat = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if badFormat {
|
||||||
|
return is, fmt.Errorf(
|
||||||
|
"migration error: found port key in unexpected format: %s", k)
|
||||||
|
}
|
||||||
|
allowHash, _ := strconv.Atoi(kParts[1])
|
||||||
|
newK := fmt.Sprintf("allow.%d.ports.%d", allowHash, portCount)
|
||||||
|
portCount++
|
||||||
|
newPorts[newK] = is.Attributes[k]
|
||||||
|
delete(is.Attributes, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range newPorts {
|
||||||
|
is.Attributes[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
|
||||||
|
return is, nil
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestComputeFirewallMigrateState(t *testing.T) {
|
||||||
|
cases := map[string]struct {
|
||||||
|
StateVersion int
|
||||||
|
Attributes map[string]string
|
||||||
|
Expected map[string]string
|
||||||
|
Meta interface{}
|
||||||
|
}{
|
||||||
|
"change scope from list to set": {
|
||||||
|
StateVersion: 0,
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"allow.#": "1",
|
||||||
|
"allow.0.protocol": "udp",
|
||||||
|
"allow.0.ports.#": "4",
|
||||||
|
"allow.0.ports.1693978638": "8080",
|
||||||
|
"allow.0.ports.172152165": "8081",
|
||||||
|
"allow.0.ports.299962681": "7072",
|
||||||
|
"allow.0.ports.3435931483": "4044",
|
||||||
|
},
|
||||||
|
Expected: map[string]string{
|
||||||
|
"allow.#": "1",
|
||||||
|
"allow.0.protocol": "udp",
|
||||||
|
"allow.0.ports.#": "4",
|
||||||
|
"allow.0.ports.0": "8080",
|
||||||
|
"allow.0.ports.1": "8081",
|
||||||
|
"allow.0.ports.2": "7072",
|
||||||
|
"allow.0.ports.3": "4044",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for tn, tc := range cases {
|
||||||
|
is := &terraform.InstanceState{
|
||||||
|
ID: "i-abc123",
|
||||||
|
Attributes: tc.Attributes,
|
||||||
|
}
|
||||||
|
is, err := resourceComputeFirewallMigrateState(
|
||||||
|
tc.StateVersion, is, tc.Meta)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bad: %s, err: %#v", tn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range tc.Expected {
|
||||||
|
if is.Attributes[k] != v {
|
||||||
|
t.Fatalf(
|
||||||
|
"bad: %s\n\n expected: %#v -> %#v\n got: %#v -> %#v\n in: %#v",
|
||||||
|
tn, k, v, k, is.Attributes[k], is.Attributes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComputeFirewallMigrateState_empty(t *testing.T) {
|
||||||
|
var is *terraform.InstanceState
|
||||||
|
var meta interface{}
|
||||||
|
|
||||||
|
// should handle nil
|
||||||
|
is, err := resourceComputeFirewallMigrateState(0, is, meta)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %#v", err)
|
||||||
|
}
|
||||||
|
if is != nil {
|
||||||
|
t.Fatalf("expected nil instancestate, got: %#v", is)
|
||||||
|
}
|
||||||
|
|
||||||
|
// should handle non-nil but empty
|
||||||
|
is = &terraform.InstanceState{}
|
||||||
|
is, err = resourceComputeFirewallMigrateState(0, is, meta)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -126,7 +126,7 @@ func testAccCheckComputeFirewallPorts(
|
||||||
func testAccComputeFirewall_basic(network, firewall string) string {
|
func testAccComputeFirewall_basic(network, firewall string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "google_compute_network" "foobar" {
|
resource "google_compute_network" "foobar" {
|
||||||
name = "firewall-test-%s"
|
name = "%s"
|
||||||
ipv4_range = "10.0.0.0/16"
|
ipv4_range = "10.0.0.0/16"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ func testAccComputeFirewall_basic(network, firewall string) string {
|
||||||
func testAccComputeFirewall_update(network, firewall string) string {
|
func testAccComputeFirewall_update(network, firewall string) string {
|
||||||
return fmt.Sprintf(`
|
return fmt.Sprintf(`
|
||||||
resource "google_compute_network" "foobar" {
|
resource "google_compute_network" "foobar" {
|
||||||
name = "firewall-test-%s"
|
name = "%s"
|
||||||
ipv4_range = "10.0.0.0/16"
|
ipv4_range = "10.0.0.0/16"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue