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"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
|
@ -18,6 +19,10 @@ func resourceComputeFirewall() *schema.Resource {
|
|||
Read: resourceComputeFirewallRead,
|
||||
Update: resourceComputeFirewallUpdate,
|
||||
Delete: resourceComputeFirewallDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
},
|
||||
SchemaVersion: 1,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
|
@ -43,10 +48,9 @@ func resourceComputeFirewall() *schema.Resource {
|
|||
},
|
||||
|
||||
"ports": &schema.Schema{
|
||||
Type: schema.TypeSet,
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: schema.HashString,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -62,6 +66,7 @@ func resourceComputeFirewall() *schema.Resource {
|
|||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"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
|
||||
// generate the same hash code no matter what is in the set.
|
||||
if v, ok := m["ports"]; ok {
|
||||
vs := v.(*schema.Set).List()
|
||||
s := make([]string, len(vs))
|
||||
for i, raw := range vs {
|
||||
s[i] = raw.(string)
|
||||
}
|
||||
s := convertStringArr(v.([]interface{}))
|
||||
sort.Strings(s)
|
||||
|
||||
for _, v := range s {
|
||||
|
@ -146,6 +147,18 @@ func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) err
|
|||
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 {
|
||||
config := meta.(*Config)
|
||||
|
||||
|
@ -168,8 +181,16 @@ func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error
|
|||
return fmt.Errorf("Error reading firewall: %s", err)
|
||||
}
|
||||
|
||||
networkUrl := strings.Split(firewall.Network, "/")
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -250,10 +271,10 @@ func resourceFirewall(
|
|||
m := v.(map[string]interface{})
|
||||
|
||||
var ports []string
|
||||
if v := m["ports"].(*schema.Set); v.Len() > 0 {
|
||||
ports = make([]string, v.Len())
|
||||
for i, v := range v.List() {
|
||||
ports[i] = v.(string)
|
||||
if v := convertStringArr(m["ports"].([]interface{})); len(v) > 0 {
|
||||
ports = make([]string, len(v))
|
||||
for i, v := range v {
|
||||
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 {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "firewall-test-%s"
|
||||
name = "%s"
|
||||
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 {
|
||||
return fmt.Sprintf(`
|
||||
resource "google_compute_network" "foobar" {
|
||||
name = "firewall-test-%s"
|
||||
name = "%s"
|
||||
ipv4_range = "10.0.0.0/16"
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue