From b6f89d3e328ef56a4cdf507909d5c85389a56663 Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Wed, 4 Mar 2015 18:51:07 +0100 Subject: [PATCH 01/20] Adding a few new resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests and docs will be added tomorrow so we can merge the new resources… --- builtin/providers/cloudstack/provider.go | 25 ++- .../resource_cloudstack_vpn_connection.go | 95 +++++++++ ...esource_cloudstack_vpn_customer_gateway.go | 193 ++++++++++++++++++ .../resource_cloudstack_vpn_gateway.go | 97 +++++++++ 4 files changed, 399 insertions(+), 11 deletions(-) create mode 100644 builtin/providers/cloudstack/resource_cloudstack_vpn_connection.go create mode 100644 builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway.go create mode 100644 builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go diff --git a/builtin/providers/cloudstack/provider.go b/builtin/providers/cloudstack/provider.go index a9913f6e8..f7ce62725 100644 --- a/builtin/providers/cloudstack/provider.go +++ b/builtin/providers/cloudstack/provider.go @@ -35,17 +35,20 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "cloudstack_disk": resourceCloudStackDisk(), - "cloudstack_egress_firewall": resourceCloudStackEgressFirewall(), - "cloudstack_firewall": resourceCloudStackFirewall(), - "cloudstack_instance": resourceCloudStackInstance(), - "cloudstack_ipaddress": resourceCloudStackIPAddress(), - "cloudstack_network": resourceCloudStackNetwork(), - "cloudstack_network_acl": resourceCloudStackNetworkACL(), - "cloudstack_network_acl_rule": resourceCloudStackNetworkACLRule(), - "cloudstack_nic": resourceCloudStackNIC(), - "cloudstack_port_forward": resourceCloudStackPortForward(), - "cloudstack_vpc": resourceCloudStackVPC(), + "cloudstack_disk": resourceCloudStackDisk(), + "cloudstack_egress_firewall": resourceCloudStackEgressFirewall(), + "cloudstack_firewall": resourceCloudStackFirewall(), + "cloudstack_instance": resourceCloudStackInstance(), + "cloudstack_ipaddress": resourceCloudStackIPAddress(), + "cloudstack_network": resourceCloudStackNetwork(), + "cloudstack_network_acl": resourceCloudStackNetworkACL(), + "cloudstack_network_acl_rule": resourceCloudStackNetworkACLRule(), + "cloudstack_nic": resourceCloudStackNIC(), + "cloudstack_port_forward": resourceCloudStackPortForward(), + "cloudstack_vpc": resourceCloudStackVPC(), + "cloudstack_vpn_connection": resourceCloudStackVPNConnection(), + "cloudstack_vpn_customer_gateway": resourceCloudStackVPNCustomerGateway(), + "cloudstack_vpn_gateway": resourceCloudStackVPNGateway(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_connection.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_connection.go new file mode 100644 index 000000000..b036890a5 --- /dev/null +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_connection.go @@ -0,0 +1,95 @@ +package cloudstack + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/xanzy/go-cloudstack/cloudstack" +) + +func resourceCloudStackVPNConnection() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackVPNConnectionCreate, + Read: resourceCloudStackVPNConnectionRead, + Delete: resourceCloudStackVPNConnectionDelete, + + Schema: map[string]*schema.Schema{ + "customergatewayid": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "vpngatewayid": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceCloudStackVPNConnectionCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Create a new parameter struct + p := cs.VPN.NewCreateVpnConnectionParams( + d.Get("customergatewayid").(string), + d.Get("vpngatewayid").(string), + ) + + // Create the new VPN Connection + v, err := cs.VPN.CreateVpnConnection(p) + if err != nil { + return fmt.Errorf("Error creating VPN Connection: %s", err) + } + + d.SetId(v.Id) + + return resourceCloudStackVPNConnectionRead(d, meta) +} + +func resourceCloudStackVPNConnectionRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Get the VPN Connection details + v, count, err := cs.VPN.GetVpnConnectionByID(d.Id()) + if err != nil { + if count == 0 { + log.Printf("[DEBUG] VPN Connection does no longer exist") + d.SetId("") + return nil + } + + return err + } + + d.Set("customergatewayid", v.S2scustomergatewayid) + d.Set("vpngatewayid", v.S2svpngatewayid) + + return nil +} + +func resourceCloudStackVPNConnectionDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Create a new parameter struct + p := cs.VPN.NewDeleteVpnConnectionParams(d.Id()) + + // Delete the VPN Connection + _, err := cs.VPN.DeleteVpnConnection(p) + if err != nil { + // This is a very poor way to be told the UUID does no longer exist :( + if strings.Contains(err.Error(), fmt.Sprintf( + "Invalid parameter id value=%s due to incorrect long value format, "+ + "or entity does not exist", d.Id())) { + return nil + } + + return fmt.Errorf("Error deleting VPN Connection: %s", err) + } + + return nil +} diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway.go new file mode 100644 index 000000000..90a03aeb0 --- /dev/null +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway.go @@ -0,0 +1,193 @@ +package cloudstack + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/xanzy/go-cloudstack/cloudstack" +) + +func resourceCloudStackVPNCustomerGateway() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackVPNCustomerGatewayCreate, + Read: resourceCloudStackVPNCustomerGatewayRead, + Update: resourceCloudStackVPNCustomerGatewayUpdate, + Delete: resourceCloudStackVPNCustomerGatewayDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "cidr": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "esp_policy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "gateway": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "ike_policy": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "ipsec_psk": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "dpd": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + + "esp_lifetime": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + + "ike_lifetime": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + }, + } +} + +func resourceCloudStackVPNCustomerGatewayCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Create a new parameter struct + p := cs.VPN.NewCreateVpnCustomerGatewayParams( + d.Get("cidr").(string), + d.Get("esp_policy").(string), + d.Get("gateway").(string), + d.Get("ike_policy").(string), + d.Get("ipsec_psk").(string), + ) + + p.SetName(d.Get("name").(string)) + + if dpd, ok := d.GetOk("dpd"); ok { + p.SetDpd(dpd.(bool)) + } + + if esplifetime, ok := d.GetOk("esp_lifetime"); ok { + p.SetEsplifetime(esplifetime.(int)) + } + + if ikelifetime, ok := d.GetOk("ike_lifetime"); ok { + p.SetIkelifetime(ikelifetime.(int)) + } + + // Create the new VPN Customer Gateway + v, err := cs.VPN.CreateVpnCustomerGateway(p) + if err != nil { + return fmt.Errorf("Error creating VPN Customer Gateway %s: %s", d.Get("name").(string), err) + } + + d.SetId(v.Id) + + return resourceCloudStackVPNCustomerGatewayRead(d, meta) +} + +func resourceCloudStackVPNCustomerGatewayRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Get the VPN Customer Gateway details + v, count, err := cs.VPN.GetVpnCustomerGatewayByID(d.Id()) + if err != nil { + if count == 0 { + log.Printf( + "[DEBUG] VPN Customer Gateway %s does no longer exist", d.Get("name").(string)) + d.SetId("") + return nil + } + + return err + } + + d.Set("name", v.Name) + d.Set("cidr", v.Cidrlist) + d.Set("esp_policy", v.Esppolicy) + d.Set("gateway", v.Gateway) + d.Set("ike_policy", v.Ikepolicy) + d.Set("ipsec_psk", v.Ipsecpsk) + d.Set("dpd", v.Dpd) + d.Set("esp_lifetime", v.Esplifetime) + d.Set("ike_lifetime", v.Ikelifetime) + + return nil +} + +func resourceCloudStackVPNCustomerGatewayUpdate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Create a new parameter struct + p := cs.VPN.NewUpdateVpnCustomerGatewayParams( + d.Get("cidr").(string), + d.Get("esp_policy").(string), + d.Get("gateway").(string), + d.Id(), + d.Get("ike_policy").(string), + d.Get("ipsec_psk").(string), + ) + + p.SetName(d.Get("name").(string)) + + if dpd, ok := d.GetOk("dpd"); ok { + p.SetDpd(dpd.(bool)) + } + + if esplifetime, ok := d.GetOk("esp_lifetime"); ok { + p.SetEsplifetime(esplifetime.(int)) + } + + if ikelifetime, ok := d.GetOk("ike_lifetime"); ok { + p.SetIkelifetime(ikelifetime.(int)) + } + + // Update the VPN Customer Gateway + _, err := cs.VPN.UpdateVpnCustomerGateway(p) + if err != nil { + return fmt.Errorf("Error updating VPN Customer Gateway %s: %s", d.Get("name").(string), err) + } + + return resourceCloudStackVPNCustomerGatewayRead(d, meta) +} + +func resourceCloudStackVPNCustomerGatewayDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Create a new parameter struct + p := cs.VPN.NewDeleteVpnCustomerGatewayParams(d.Id()) + + // Delete the VPN Customer Gateway + _, err := cs.VPN.DeleteVpnCustomerGateway(p) + if err != nil { + // This is a very poor way to be told the UUID does no longer exist :( + if strings.Contains(err.Error(), fmt.Sprintf( + "Invalid parameter id value=%s due to incorrect long value format, "+ + "or entity does not exist", d.Id())) { + return nil + } + + return fmt.Errorf("Error deleting VPN Customer Gateway %s: %s", d.Get("name").(string), err) + } + + return nil +} diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go new file mode 100644 index 000000000..650df6530 --- /dev/null +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go @@ -0,0 +1,97 @@ +package cloudstack + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/xanzy/go-cloudstack/cloudstack" +) + +func resourceCloudStackVPNGateway() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudStackVPNGatewayCreate, + Read: resourceCloudStackVPNGatewayRead, + Delete: resourceCloudStackVPNGatewayDelete, + + Schema: map[string]*schema.Schema{ + "vpc": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "publicip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceCloudStackVPNGatewayCreate(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Retrieve the VPC UUID + vpcid, e := retrieveUUID(cs, "vpc", d.Get("vpc").(string)) + if e != nil { + return e.Error() + } + + // Create a new parameter struct + p := cs.VPN.NewCreateVpnGatewayParams(vpcid) + + // Create the new VPN Gateway + v, err := cs.VPN.CreateVpnGateway(p) + if err != nil { + return fmt.Errorf("Error creating VPN Gateway for VPC %s: %s", d.Get("vpc").(string), err) + } + + d.SetId(v.Id) + + return resourceCloudStackVPNGatewayRead(d, meta) +} + +func resourceCloudStackVPNGatewayRead(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Get the VPN Gateway details + v, count, err := cs.VPN.GetVpnGatewayByID(d.Id()) + if err != nil { + if count == 0 { + log.Printf( + "[DEBUG] VPN Gateway for VPC %s does no longer exist", d.Get("vpc").(string)) + d.SetId("") + return nil + } + + return err + } + + d.Set("publicip", v.Publicip) + + return nil +} + +func resourceCloudStackVPNGatewayDelete(d *schema.ResourceData, meta interface{}) error { + cs := meta.(*cloudstack.CloudStackClient) + + // Create a new parameter struct + p := cs.VPN.NewDeleteVpnGatewayParams(d.Id()) + + // Delete the VPN Gateway + _, err := cs.VPN.DeleteVpnGateway(p) + if err != nil { + // This is a very poor way to be told the UUID does no longer exist :( + if strings.Contains(err.Error(), fmt.Sprintf( + "Invalid parameter id value=%s due to incorrect long value format, "+ + "or entity does not exist", d.Id())) { + return nil + } + + return fmt.Errorf("Error deleting VPN Gateway for VPC %s: %s", d.Get("vpc").(string), err) + } + + return nil +} From bb7ef8db67d5e663b11713aa9fb8a4d2cce59e4f Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Mon, 9 Mar 2015 14:00:29 +0100 Subject: [PATCH 02/20] Adding tests and docs for the new VPN resources And did some (very) minor refactoring in the existing docs --- builtin/providers/cloudstack/provider_test.go | 3 +- .../resource_cloudstack_ipaddress_test.go | 2 +- ...source_cloudstack_network_acl_rule_test.go | 4 +- .../resource_cloudstack_network_acl_test.go | 2 +- .../resource_cloudstack_network_test.go | 2 +- .../resource_cloudstack_vpc_test.go | 6 +- ...resource_cloudstack_vpn_connection_test.go | 142 +++++++++++ ...ce_cloudstack_vpn_customer_gateway_test.go | 225 ++++++++++++++++++ .../resource_cloudstack_vpn_gateway.go | 4 +- .../resource_cloudstack_vpn_gateway_test.go | 101 ++++++++ .../r/egress_firewall.html.markdown | 2 +- .../cloudstack/r/firewall.html.markdown | 2 +- .../r/network_acl_rule.html.markdown | 2 +- .../cloudstack/r/vpn_connection.html.markdown | 38 +++ .../r/vpn_customer_gateway.html.markdown | 59 +++++ .../cloudstack/r/vpn_gateway.html.markdown | 35 +++ website/source/layouts/cloudstack.erb | 116 +++++---- 17 files changed, 679 insertions(+), 66 deletions(-) create mode 100644 builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go create mode 100644 builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go create mode 100644 builtin/providers/cloudstack/resource_cloudstack_vpn_gateway_test.go create mode 100644 website/source/docs/providers/cloudstack/r/vpn_connection.html.markdown create mode 100644 website/source/docs/providers/cloudstack/r/vpn_customer_gateway.html.markdown create mode 100644 website/source/docs/providers/cloudstack/r/vpn_gateway.html.markdown diff --git a/builtin/providers/cloudstack/provider_test.go b/builtin/providers/cloudstack/provider_test.go index a13839177..537a2664f 100644 --- a/builtin/providers/cloudstack/provider_test.go +++ b/builtin/providers/cloudstack/provider_test.go @@ -51,7 +51,8 @@ var CLOUDSTACK_NETWORK_1_OFFERING = "" var CLOUDSTACK_NETWORK_1_IPADDRESS = "" var CLOUDSTACK_NETWORK_2 = "" var CLOUDSTACK_NETWORK_2_IPADDRESS = "" -var CLOUDSTACK_VPC_CIDR = "" +var CLOUDSTACK_VPC_CIDR_1 = "" +var CLOUDSTACK_VPC_CIDR_2 = "" var CLOUDSTACK_VPC_OFFERING = "" var CLOUDSTACK_VPC_NETWORK_CIDR = "" var CLOUDSTACK_VPC_NETWORK_OFFERING = "" diff --git a/builtin/providers/cloudstack/resource_cloudstack_ipaddress_test.go b/builtin/providers/cloudstack/resource_cloudstack_ipaddress_test.go index 5b1fc9a31..dfdeba209 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_ipaddress_test.go +++ b/builtin/providers/cloudstack/resource_cloudstack_ipaddress_test.go @@ -132,6 +132,6 @@ resource "cloudstack_vpc" "foobar" { resource "cloudstack_ipaddress" "foo" { vpc = "${cloudstack_vpc.foobar.name}" }`, - CLOUDSTACK_VPC_CIDR, + CLOUDSTACK_VPC_CIDR_1, CLOUDSTACK_VPC_OFFERING, CLOUDSTACK_ZONE) diff --git a/builtin/providers/cloudstack/resource_cloudstack_network_acl_rule_test.go b/builtin/providers/cloudstack/resource_cloudstack_network_acl_rule_test.go index 037b9d10b..dbceb8d8d 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_network_acl_rule_test.go +++ b/builtin/providers/cloudstack/resource_cloudstack_network_acl_rule_test.go @@ -196,7 +196,7 @@ resource "cloudstack_network_acl_rule" "foo" { traffic_type = "ingress" } }`, - CLOUDSTACK_VPC_CIDR, + CLOUDSTACK_VPC_CIDR_1, CLOUDSTACK_VPC_OFFERING, CLOUDSTACK_ZONE) @@ -233,6 +233,6 @@ resource "cloudstack_network_acl_rule" "foo" { traffic_type = "egress" } }`, - CLOUDSTACK_VPC_CIDR, + CLOUDSTACK_VPC_CIDR_1, CLOUDSTACK_VPC_OFFERING, CLOUDSTACK_ZONE) diff --git a/builtin/providers/cloudstack/resource_cloudstack_network_acl_test.go b/builtin/providers/cloudstack/resource_cloudstack_network_acl_test.go index e625d4c2d..9bf0bb0cf 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_network_acl_test.go +++ b/builtin/providers/cloudstack/resource_cloudstack_network_acl_test.go @@ -112,6 +112,6 @@ resource "cloudstack_network_acl" "foo" { description = "terraform-acl-text" vpc = "${cloudstack_vpc.foobar.name}" }`, - CLOUDSTACK_VPC_CIDR, + CLOUDSTACK_VPC_CIDR_1, CLOUDSTACK_VPC_OFFERING, CLOUDSTACK_ZONE) diff --git a/builtin/providers/cloudstack/resource_cloudstack_network_test.go b/builtin/providers/cloudstack/resource_cloudstack_network_test.go index 750761f02..d936f8cb0 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_network_test.go +++ b/builtin/providers/cloudstack/resource_cloudstack_network_test.go @@ -186,7 +186,7 @@ resource "cloudstack_network" "foo" { aclid = "${cloudstack_network_acl.foo.id}" zone = "${cloudstack_vpc.foobar.zone}" }`, - CLOUDSTACK_VPC_CIDR, + CLOUDSTACK_VPC_CIDR_1, CLOUDSTACK_VPC_OFFERING, CLOUDSTACK_ZONE, CLOUDSTACK_VPC_NETWORK_CIDR, diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpc_test.go b/builtin/providers/cloudstack/resource_cloudstack_vpc_test.go index bf4e8f448..07861a091 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_vpc_test.go +++ b/builtin/providers/cloudstack/resource_cloudstack_vpc_test.go @@ -72,8 +72,8 @@ func testAccCheckCloudStackVPCAttributes( return fmt.Errorf("Bad display text: %s", vpc.Displaytext) } - if vpc.Cidr != CLOUDSTACK_VPC_CIDR { - return fmt.Errorf("Bad VPC offering: %s", vpc.Cidr) + if vpc.Cidr != CLOUDSTACK_VPC_CIDR_1 { + return fmt.Errorf("Bad VPC CIDR: %s", vpc.Cidr) } return nil @@ -113,6 +113,6 @@ resource "cloudstack_vpc" "foo" { vpc_offering = "%s" zone = "%s" }`, - CLOUDSTACK_VPC_CIDR, + CLOUDSTACK_VPC_CIDR_1, CLOUDSTACK_VPC_OFFERING, CLOUDSTACK_ZONE) diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go new file mode 100644 index 000000000..ff7a46fd3 --- /dev/null +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go @@ -0,0 +1,142 @@ +package cloudstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/xanzy/go-cloudstack/cloudstack" +) + +func TestAccCloudStackVPNConnection_basic(t *testing.T) { + var vpnConnection cloudstack.VpnConnection + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudStackVPNConnectionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCloudStackVPNConnection_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudStackVPNConnectionExists( + "cloudstack_vpn_connection.foo", &vpnConnection), + ), + }, + }, + }) +} + +func testAccCheckCloudStackVPNConnectionExists( + n string, vpnConnection *cloudstack.VpnConnection) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No VPN Connection ID is set") + } + + cs := testAccProvider.Meta().(*cloudstack.CloudStackClient) + v, _, err := cs.VPN.GetVpnConnectionByID(rs.Primary.ID) + + if err != nil { + return err + } + + if v.Id != rs.Primary.ID { + return fmt.Errorf("VPN Connection not found") + } + + *vpnConnection = *v + + return nil + } +} + +func testAccCheckCloudStackVPNConnectionDestroy(s *terraform.State) error { + cs := testAccProvider.Meta().(*cloudstack.CloudStackClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "cloudstack_vpn_connection" { + continue + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No VPN Connection ID is set") + } + + p := cs.VPN.NewDeleteVpnConnectionParams(rs.Primary.ID) + _, err := cs.VPN.DeleteVpnConnection(p) + + if err != nil { + return fmt.Errorf( + "Error deleting VPN Connection (%s): %s", + rs.Primary.ID, err) + } + } + + return nil +} + +var testAccCloudStackVPNConnection_basic = fmt.Sprintf(` +resource "cloudstack_vpc" "foo" { + name = "terraform-vpc" + display_text = "terraform-vpc-text" + cidr = "%s" + vpc_offering = "%s" + zone = "%s" +} + +resource "cloudstack_vpc" "bar" { + name = "terraform-vpc" + display_text = "terraform-vpc-text" + cidr = "%s" + vpc_offering = "%s" + zone = "%s" +} + +resource "cloudstack_vpn_gateway" "foo" { + vpc = "${cloudstack_vpc.foo.name}" +} + +resource "cloudstack_vpn_gateway" "bar" { + vpc = "${cloudstack_vpc.bar.name}" +} + +resource "cloudstack_vpn_customer_gateway" "foo" { + name = "terraform-foo" + cidr = "${cloudstack_vpc.foo.cidr}" + esp_policy = "aes256-sha1" + gateway = "${cloudstack_vpn_gateway.foo.publicip}" + ike_policy = "aes256-sha1" + ipsec_psk = "terraform" +} + +resource "cloudstack_vpn_customer_gateway" "bar" { + name = "terraform-bar" + cidr = "${cloudstack_vpc.bar.cidr}" + esp_policy = "aes256-sha1" + gateway = "${cloudstack_vpn_gateway.bar.publicip}" + ike_policy = "aes256-sha1" + ipsec_psk = "terraform" +} + +resource "cloudstack_vpn_connection" "foo-bar" { + customergatewayid = "${cloudstack_vpn_customer_gateway.foo.id}" + vpngatewayid = "${cloudstack_vpn_gateway.bar.id}" +} + +resource "cloudstack_vpn_connection" "bar-foo" { + customergatewayid = "${cloudstack_vpn_customer_gateway.bar.id}" + vpngatewayid = "${cloudstack_vpn_gateway.foo.id}" +}`, + CLOUDSTACK_VPC_CIDR_1, + CLOUDSTACK_VPC_OFFERING, + CLOUDSTACK_ZONE, + CLOUDSTACK_VPC_CIDR_2, + CLOUDSTACK_VPC_OFFERING, + CLOUDSTACK_ZONE) diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go new file mode 100644 index 000000000..9475e31a3 --- /dev/null +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go @@ -0,0 +1,225 @@ +package cloudstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/xanzy/go-cloudstack/cloudstack" +) + +func TestAccCloudStackVPNCustomerGateway_basic(t *testing.T) { + var vpnCustomerGateway cloudstack.VpnCustomerGateway + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudStackVPNCustomerGatewayDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCloudStackVPNCustomerGateway_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudStackVPNCustomerGatewayExists( + "cloudstack_vpn_connection.foo", &vpnCustomerGateway), + testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.foo", "name", "terraform-foo"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.bar", "name", "terraform-bar"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.foo", "ike_policy", "aes256-sha1"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.bar", "esp_policy", "aes256-sha1"), + ), + }, + }, + }) +} + +func TestAccCloudStackVPNCustomerGateway_update(t *testing.T) { + var nic cloudstack.Nic + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudStackNICDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: TestAccCloudStackVPNCustomerGateway_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudStackVPNCustomerGatewayExists( + "cloudstack_vpn_connection.foo", &vpnCustomerGateway), + testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.foo", "name", "terraform-foo"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.bar", "name", "terraform-bar"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.foo", "ike_policy", "aes256-sha1"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.bar", "esp_policy", "aes256-sha1"), + ), + }, + + resource.TestStep{ + Config: TestAccCloudStackVPNCustomerGateway_update, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudStackVPNCustomerGatewayExists( + "cloudstack_vpn_connection.foo", &vpnCustomerGateway), + testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.foo", "name", "terraform-foo-bar"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.bar", "name", "terraform-bar-foo"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.foo", "ike_policy", "3des-md5"), + resource.TestCheckResourceAttr( + "cloudstack_vpn_connection.bar", "esp_policy", "3des-md5"), + ), + }, + }, + }) +} + +func testAccCheckCloudStackVPNCustomerGatewayExists( + n string, vpnCustomerGateway *cloudstack.VpnCustomerGateway) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No VPN CustomerGateway ID is set") + } + + cs := testAccProvider.Meta().(*cloudstack.CloudStackClient) + v, _, err := cs.VPN.GetVpnCustomerGatewayByID(rs.Primary.ID) + + if err != nil { + return err + } + + if v.Id != rs.Primary.ID { + return fmt.Errorf("VPN CustomerGateway not found") + } + + *vpnCustomerGateway = *v + + return nil + } +} + +func testAccCheckCloudStackVPNCustomerGatewayAttributes( + vpnCustomerGateway *cloudstack.VpnCustomerGateway) resource.TestCheckFunc { + return func(s *terraform.State) error { + + if vpnCustomerGateway.Esppolicy != "aes256-sha1" { + return fmt.Errorf("Bad ESP policy: %s", vpnCustomerGateway.Esppolicy) + } + + if vpnCustomerGateway.Ikepolicy != "aes256-sha1" { + return fmt.Errorf("Bad IKE policy: %s", vpnCustomerGateway.Ikepolicy) + } + + if vpnCustomerGateway.Ipsecpsk != "terraform" { + return fmt.Errorf("Bad IPSEC pre-shared key: %s", vpnCustomerGateway.Ipsecpsk) + } + + return nil + } +} + +func testAccCheckCloudStackVPNCustomerGatewayDestroy(s *terraform.State) error { + cs := testAccProvider.Meta().(*cloudstack.CloudStackClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "cloudstack_vpn_connection" { + continue + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No VPN Customer Gateway ID is set") + } + + p := cs.VPN.NewDeleteVpnCustomerGatewayParams(rs.Primary.ID) + _, err := cs.VPN.DeleteVpnCustomerGateway(p) + + if err != nil { + return fmt.Errorf( + "Error deleting VPN Customer Gateway (%s): %s", + rs.Primary.ID, err) + } + } + + return nil +} + +var testAccCloudStackVPNCustomerGateway_basic = fmt.Sprintf(` +resource "cloudstack_vpc" "foo" { + name = "terraform-vpc" + display_text = "terraform-vpc-text" + cidr = "%s" + vpc_offering = "%s" + zone = "%s" +} + +resource "cloudstack_vpc" "bar" { + name = "terraform-vpc" + display_text = "terraform-vpc-text" + cidr = "%s" + vpc_offering = "%s" + zone = "%s" +} + +resource "cloudstack_vpn_gateway" "foo" { + vpc = "${cloudstack_vpc.foo.name}" +} + +resource "cloudstack_vpn_gateway" "bar" { + vpc = "${cloudstack_vpc.bar.name}" +} + +resource "cloudstack_vpn_customer_gateway" "foo" { + name = "terraform-foo" + cidr = "${cloudstack_vpc.foo.cidr}" + esp_policy = "aes256-sha1" + gateway = "${cloudstack_vpn_gateway.foo.publicip}" + ike_policy = "aes256-sha1" + ipsec_psk = "terraform" +} + +resource "cloudstack_vpn_customer_gateway" "bar" { + name = "terraform-bar" + cidr = "${cloudstack_vpc.bar.cidr}" + esp_policy = "aes256-sha1" + gateway = "${cloudstack_vpn_gateway.bar.publicip}" + ike_policy = "aes256-sha1" + ipsec_psk = "terraform" +}`, + CLOUDSTACK_VPC_CIDR_1, + CLOUDSTACK_VPC_OFFERING, + CLOUDSTACK_ZONE, + CLOUDSTACK_VPC_CIDR_2, + CLOUDSTACK_VPC_OFFERING, + CLOUDSTACK_ZONE) + +var testAccCloudStackVPNCustomerGateway_update = fmt.Sprintf(` +resource "cloudstack_vpn_customer_gateway" "foo" { + name = "terraform-foo-bar" + cidr = "${cloudstack_vpc.foo.cidr}" + esp_policy = "3des-md5" + gateway = "${cloudstack_vpn_gateway.foo.publicip}" + ike_policy = "3des-md5" + ipsec_psk = "terraform" +} + +resource "cloudstack_vpn_customer_gateway" "bar" { + name = "terraform-bar-foo" + cidr = "${cloudstack_vpc.bar.cidr}" + esp_policy = "3des-md5" + gateway = "${cloudstack_vpn_gateway.bar.publicip}" + ike_policy = "3des-md5" + ipsec_psk = "terraform" +}`) diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go index 650df6530..063c31777 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway.go @@ -22,7 +22,7 @@ func resourceCloudStackVPNGateway() *schema.Resource { ForceNew: true, }, - "publicip": &schema.Schema{ + "public_ip": &schema.Schema{ Type: schema.TypeString, Computed: true, }, @@ -69,7 +69,7 @@ func resourceCloudStackVPNGatewayRead(d *schema.ResourceData, meta interface{}) return err } - d.Set("publicip", v.Publicip) + d.Set("public_ip", v.Publicip) return nil } diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway_test.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway_test.go new file mode 100644 index 000000000..db6c0085a --- /dev/null +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_gateway_test.go @@ -0,0 +1,101 @@ +package cloudstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/xanzy/go-cloudstack/cloudstack" +) + +func TestAccCloudStackVPNGateway_basic(t *testing.T) { + var vpnGateway cloudstack.VpnGateway + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudStackVPNGatewayDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCloudStackVPNGateway_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckCloudStackVPNGatewayExists( + "cloudstack_vpn_gateway.foo", &vpnGateway), + resource.TestCheckResourceAttr( + "cloudstack_vpn_gateway.foo", "vpc", "terraform-vpc"), + ), + }, + }, + }) +} + +func testAccCheckCloudStackVPNGatewayExists( + n string, vpnGateway *cloudstack.VpnGateway) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No VPN Gateway ID is set") + } + + cs := testAccProvider.Meta().(*cloudstack.CloudStackClient) + v, _, err := cs.VPN.GetVpnGatewayByID(rs.Primary.ID) + + if err != nil { + return err + } + + if v.Id != rs.Primary.ID { + return fmt.Errorf("VPN Gateway not found") + } + + *vpnGateway = *v + + return nil + } +} + +func testAccCheckCloudStackVPNGatewayDestroy(s *terraform.State) error { + cs := testAccProvider.Meta().(*cloudstack.CloudStackClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "cloudstack_vpn_gateway" { + continue + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No VPN Gateway ID is set") + } + + p := cs.VPN.NewDeleteVpnGatewayParams(rs.Primary.ID) + _, err := cs.VPN.DeleteVpnGateway(p) + + if err != nil { + return fmt.Errorf( + "Error deleting VPN Gateway (%s): %s", + rs.Primary.ID, err) + } + } + + return nil +} + +var testAccCloudStackVPNGateway_basic = fmt.Sprintf(` +resource "cloudstack_vpc" "foo" { + name = "terraform-vpc" + display_text = "terraform-vpc-text" + cidr = "%s" + vpc_offering = "%s" + zone = "%s" +} + +resource "cloudstack_vpn_gateway" "foo" { + vpc = "${cloudstack_vpc.foo.name}" +}`, + CLOUDSTACK_VPC_CIDR_1, + CLOUDSTACK_VPC_OFFERING, + CLOUDSTACK_ZONE) diff --git a/website/source/docs/providers/cloudstack/r/egress_firewall.html.markdown b/website/source/docs/providers/cloudstack/r/egress_firewall.html.markdown index 17fa20927..b905bc0e9 100644 --- a/website/source/docs/providers/cloudstack/r/egress_firewall.html.markdown +++ b/website/source/docs/providers/cloudstack/r/egress_firewall.html.markdown @@ -58,4 +58,4 @@ The `rule` block supports: The following attributes are exported: -* `ID` - The network ID for which the egress firewall rules are created. +* `id` - The network ID for which the egress firewall rules are created. diff --git a/website/source/docs/providers/cloudstack/r/firewall.html.markdown b/website/source/docs/providers/cloudstack/r/firewall.html.markdown index 1c659e6bf..8b8aa0089 100644 --- a/website/source/docs/providers/cloudstack/r/firewall.html.markdown +++ b/website/source/docs/providers/cloudstack/r/firewall.html.markdown @@ -58,4 +58,4 @@ The `rule` block supports: The following attributes are exported: -* `ID` - The IP address ID for which the firewall rules are created. +* `id` - The IP address ID for which the firewall rules are created. diff --git a/website/source/docs/providers/cloudstack/r/network_acl_rule.html.markdown b/website/source/docs/providers/cloudstack/r/network_acl_rule.html.markdown index fb6b0891f..f82b8f446 100644 --- a/website/source/docs/providers/cloudstack/r/network_acl_rule.html.markdown +++ b/website/source/docs/providers/cloudstack/r/network_acl_rule.html.markdown @@ -66,4 +66,4 @@ The `rule` block supports: The following attributes are exported: -* `ID` - The ACL ID for which the rules are created. +* `id` - The ACL ID for which the rules are created. diff --git a/website/source/docs/providers/cloudstack/r/vpn_connection.html.markdown b/website/source/docs/providers/cloudstack/r/vpn_connection.html.markdown new file mode 100644 index 000000000..3ecf17cbc --- /dev/null +++ b/website/source/docs/providers/cloudstack/r/vpn_connection.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_vpn_connection" +sidebar_current: "docs-cloudstack-resource-vpn-connection" +description: |- + Creates a site to site VPN connection. +--- + +# cloudstack\_vpn\_connection + +Creates a site to site VPN connection. + +## Example Usage + +Basic usage: + +``` +resource "cloudstack_vpn_connection" "default" { + customergatewayid = "xxx" + vpngatewayid = "xxx" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `customergatewayid` - (Required) The Customer Gateway ID to connect. + Changing this forces a new resource to be created. + +* `vpngatewayid` - (Required) The VPN Gateway ID to connect. + Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the VPN Connection. diff --git a/website/source/docs/providers/cloudstack/r/vpn_customer_gateway.html.markdown b/website/source/docs/providers/cloudstack/r/vpn_customer_gateway.html.markdown new file mode 100644 index 000000000..84183b8d6 --- /dev/null +++ b/website/source/docs/providers/cloudstack/r/vpn_customer_gateway.html.markdown @@ -0,0 +1,59 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_vpn_customer_gateway" +sidebar_current: "docs-cloudstack-resource-vpn-customer-gateway" +description: |- + Creates a site to site VPN local customer gateway. +--- + +# cloudstack\_vpn\_customer\_gateway + +Creates a site to site VPN local customer gateway. + +## Example Usage + +Basic usage: + +``` +resource "cloudstack_vpn_customer_gateway" "default" { + name = "test-vpc" + cidr = "10.0.0.0/8" + esp_policy = "aes256-sha1" + gateway = "192.168.0.1" + ike_policy = "aes256-sha1" + ipsec_psk = "terraform" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the VPN Customer Gateway. + +* `cidr` - (Required) The CIDR block that needs to be routed through this gateway. + +* `esp_policy` - (Required) The ESP policy to use for this VPN Customer Gateway. + +* `gateway` - (Required) The public IP address of the related VPN Gateway. + +* `ike_policy` - (Required) The IKE policy to use for this VPN Customer Gateway. + +* `ipsec_psk` - (Required) The IPSEC pre-shared key used for this gateway. + +* `dpd` - (Optional) If DPD is enabled for the related VPN connection (defaults false) + +* `esp_lifetime` - (Optional) The ESP lifetime of phase 2 VPN connection to this + VPN Customer Gateway in seconds (defaults 86400) + +* `ike_lifetime` - (Optional) The IKE lifetime of phase 2 VPN connection to this + VPN Customer Gateway in seconds (defaults 86400) + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the VPN Customer Gateway. +* `dpd` - Enable or disable DPD is enabled for the related VPN connection. +* `esp_lifetime` - The ESP lifetime of phase 2 VPN connection to this VPN Customer Gateway. +* `ike_lifetime` - The IKE lifetime of phase 2 VPN connection to this VPN Customer Gateway. diff --git a/website/source/docs/providers/cloudstack/r/vpn_gateway.html.markdown b/website/source/docs/providers/cloudstack/r/vpn_gateway.html.markdown new file mode 100644 index 000000000..10aabd796 --- /dev/null +++ b/website/source/docs/providers/cloudstack/r/vpn_gateway.html.markdown @@ -0,0 +1,35 @@ +--- +layout: "cloudstack" +page_title: "CloudStack: cloudstack_vpn_gateway" +sidebar_current: "docs-cloudstack-resource-vpn-gateway" +description: |- + Creates a site to site VPN local gateway. +--- + +# cloudstack\_vpn\_gateway + +Creates a site to site VPN local gateway. + +## Example Usage + +Basic usage: + +``` +resource "cloudstack_vpn_gateway" "default" { + vpc = "test-vpc" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `vpc` - (Required) The name of the VPC for which to create the VPN Gateway. + Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the VPN Gateway. +* `public_ip` - The public IP address associated with the VPN Gateway. diff --git a/website/source/layouts/cloudstack.erb b/website/source/layouts/cloudstack.erb index a0e137aae..ee1ae6587 100644 --- a/website/source/layouts/cloudstack.erb +++ b/website/source/layouts/cloudstack.erb @@ -1,66 +1,78 @@ <% wrap_layout :inner do %> - <% content_for :sidebar do %> - + <% end %> + + <%= yield %> +<% end %> From bb88adb5a326f24e40add8b469825de6e6044888 Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Mon, 9 Mar 2015 14:02:18 +0100 Subject: [PATCH 03/20] Fixing a corner case while retrieving a template UUID Added some logic to the go-cloudstack package to support a more customised call to GetTemplateID in order to get the correct/expected UUID. --- .../cloudstack/resource_cloudstack_instance.go | 12 ++++++------ builtin/providers/cloudstack/resources.go | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/builtin/providers/cloudstack/resource_cloudstack_instance.go b/builtin/providers/cloudstack/resource_cloudstack_instance.go index 600001a27..f0e52b588 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_instance.go +++ b/builtin/providers/cloudstack/resource_cloudstack_instance.go @@ -95,18 +95,18 @@ func resourceCloudStackInstanceCreate(d *schema.ResourceData, meta interface{}) return e.Error() } - // Retrieve the template UUID - templateid, e := retrieveUUID(cs, "template", d.Get("template").(string)) - if e != nil { - return e.Error() - } - // Retrieve the zone object zone, _, err := cs.Zone.GetZoneByName(d.Get("zone").(string)) if err != nil { return err } + // Retrieve the template UUID + templateid, e := retrieveTemplateUUID(cs, zone.Id, d.Get("template").(string)) + if e != nil { + return e.Error() + } + // Create a new parameter struct p := cs.VirtualMachine.NewDeployVirtualMachineParams(serviceofferingid, templateid, zone.Id) diff --git a/builtin/providers/cloudstack/resources.go b/builtin/providers/cloudstack/resources.go index acef7b3da..76d38eb7c 100644 --- a/builtin/providers/cloudstack/resources.go +++ b/builtin/providers/cloudstack/resources.go @@ -40,8 +40,6 @@ func retrieveUUID(cs *cloudstack.CloudStackClient, name, value string) (uuid str uuid, err = cs.VPC.GetVPCOfferingID(value) case "vpc": uuid, err = cs.VPC.GetVPCID(value) - case "template": - uuid, err = cs.Template.GetTemplateID(value, "executable") case "network": uuid, err = cs.Network.GetNetworkID(value) case "zone": @@ -71,6 +69,22 @@ func retrieveUUID(cs *cloudstack.CloudStackClient, name, value string) (uuid str return uuid, nil } +func retrieveTemplateUUID(cs *cloudstack.CloudStackClient, zoneid, value string) (uuid string, e *retrieveError) { + // If the supplied value isn't a UUID, try to retrieve the UUID ourselves + if isUUID(value) { + return value, nil + } + + log.Printf("[DEBUG] Retrieving UUID of template: %s", value) + + uuid, err := cs.Template.GetTemplateID(value, "executable", zoneid) + if err != nil { + return uuid, &retrieveError{name: "template", value: value, err: err} + } + + return uuid, nil +} + func isUUID(s string) bool { re := regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`) return re.MatchString(s) From 94608fc4bc318604b3ba47125660d6373ea76cfa Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Mon, 9 Mar 2015 17:44:09 +0100 Subject: [PATCH 04/20] Fixing up the tests to make them pass correctly --- builtin/providers/cloudstack/provider.go | 2 +- ...resource_cloudstack_vpn_connection_test.go | 14 ++--- ...ce_cloudstack_vpn_customer_gateway_test.go | 54 +++++++++---------- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/builtin/providers/cloudstack/provider.go b/builtin/providers/cloudstack/provider.go index f7ce62725..8bea67ef5 100644 --- a/builtin/providers/cloudstack/provider.go +++ b/builtin/providers/cloudstack/provider.go @@ -30,7 +30,7 @@ func Provider() terraform.ResourceProvider { "timeout": &schema.Schema{ Type: schema.TypeInt, Required: true, - DefaultFunc: schema.EnvDefaultFunc("CLOUDSTACK_TIMEOUT", 180), + DefaultFunc: schema.EnvDefaultFunc("CLOUDSTACK_TIMEOUT", 300), }, }, diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go index ff7a46fd3..1b9d9920a 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_connection_test.go @@ -21,7 +21,9 @@ func TestAccCloudStackVPNConnection_basic(t *testing.T) { Config: testAccCloudStackVPNConnection_basic, Check: resource.ComposeTestCheckFunc( testAccCheckCloudStackVPNConnectionExists( - "cloudstack_vpn_connection.foo", &vpnConnection), + "cloudstack_vpn_connection.foo-bar", &vpnConnection), + testAccCheckCloudStackVPNConnectionExists( + "cloudstack_vpn_connection.bar-foo", &vpnConnection), ), }, }, @@ -84,16 +86,14 @@ func testAccCheckCloudStackVPNConnectionDestroy(s *terraform.State) error { var testAccCloudStackVPNConnection_basic = fmt.Sprintf(` resource "cloudstack_vpc" "foo" { - name = "terraform-vpc" - display_text = "terraform-vpc-text" + name = "terraform-vpc-foo" cidr = "%s" vpc_offering = "%s" zone = "%s" } resource "cloudstack_vpc" "bar" { - name = "terraform-vpc" - display_text = "terraform-vpc-text" + name = "terraform-vpc-bar" cidr = "%s" vpc_offering = "%s" zone = "%s" @@ -111,7 +111,7 @@ resource "cloudstack_vpn_customer_gateway" "foo" { name = "terraform-foo" cidr = "${cloudstack_vpc.foo.cidr}" esp_policy = "aes256-sha1" - gateway = "${cloudstack_vpn_gateway.foo.publicip}" + gateway = "${cloudstack_vpn_gateway.foo.public_ip}" ike_policy = "aes256-sha1" ipsec_psk = "terraform" } @@ -120,7 +120,7 @@ resource "cloudstack_vpn_customer_gateway" "bar" { name = "terraform-bar" cidr = "${cloudstack_vpc.bar.cidr}" esp_policy = "aes256-sha1" - gateway = "${cloudstack_vpn_gateway.bar.publicip}" + gateway = "${cloudstack_vpn_gateway.bar.public_ip}" ike_policy = "aes256-sha1" ipsec_psk = "terraform" } diff --git a/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go b/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go index 9475e31a3..b468c76fe 100644 --- a/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go +++ b/builtin/providers/cloudstack/resource_cloudstack_vpn_customer_gateway_test.go @@ -21,16 +21,16 @@ func TestAccCloudStackVPNCustomerGateway_basic(t *testing.T) { Config: testAccCloudStackVPNCustomerGateway_basic, Check: resource.ComposeTestCheckFunc( testAccCheckCloudStackVPNCustomerGatewayExists( - "cloudstack_vpn_connection.foo", &vpnCustomerGateway), + "cloudstack_vpn_customer_gateway.foo", &vpnCustomerGateway), testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.foo", "name", "terraform-foo"), + "cloudstack_vpn_customer_gateway.foo", "name", "terraform-foo"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.bar", "name", "terraform-bar"), + "cloudstack_vpn_customer_gateway.bar", "name", "terraform-bar"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.foo", "ike_policy", "aes256-sha1"), + "cloudstack_vpn_customer_gateway.foo", "ike_policy", "aes256-sha1"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.bar", "esp_policy", "aes256-sha1"), + "cloudstack_vpn_customer_gateway.bar", "esp_policy", "aes256-sha1"), ), }, }, @@ -38,44 +38,44 @@ func TestAccCloudStackVPNCustomerGateway_basic(t *testing.T) { } func TestAccCloudStackVPNCustomerGateway_update(t *testing.T) { - var nic cloudstack.Nic + var vpnCustomerGateway cloudstack.VpnCustomerGateway resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckCloudStackNICDestroy, + CheckDestroy: testAccCheckCloudStackVPNCustomerGatewayDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: TestAccCloudStackVPNCustomerGateway_basic, + Config: testAccCloudStackVPNCustomerGateway_basic, Check: resource.ComposeTestCheckFunc( testAccCheckCloudStackVPNCustomerGatewayExists( - "cloudstack_vpn_connection.foo", &vpnCustomerGateway), + "cloudstack_vpn_customer_gateway.foo", &vpnCustomerGateway), testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.foo", "name", "terraform-foo"), + "cloudstack_vpn_customer_gateway.foo", "name", "terraform-foo"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.bar", "name", "terraform-bar"), + "cloudstack_vpn_customer_gateway.bar", "name", "terraform-bar"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.foo", "ike_policy", "aes256-sha1"), + "cloudstack_vpn_customer_gateway.foo", "ike_policy", "aes256-sha1"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.bar", "esp_policy", "aes256-sha1"), + "cloudstack_vpn_customer_gateway.bar", "esp_policy", "aes256-sha1"), ), }, resource.TestStep{ - Config: TestAccCloudStackVPNCustomerGateway_update, + Config: testAccCloudStackVPNCustomerGateway_update, Check: resource.ComposeTestCheckFunc( testAccCheckCloudStackVPNCustomerGatewayExists( - "cloudstack_vpn_connection.foo", &vpnCustomerGateway), + "cloudstack_vpn_customer_gateway.foo", &vpnCustomerGateway), testAccCheckCloudStackVPNCustomerGatewayAttributes(&vpnCustomerGateway), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.foo", "name", "terraform-foo-bar"), + "cloudstack_vpn_customer_gateway.foo", "name", "terraform-foo-bar"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.bar", "name", "terraform-bar-foo"), + "cloudstack_vpn_customer_gateway.bar", "name", "terraform-bar-foo"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.foo", "ike_policy", "3des-md5"), + "cloudstack_vpn_customer_gateway.foo", "ike_policy", "3des-md5"), resource.TestCheckResourceAttr( - "cloudstack_vpn_connection.bar", "esp_policy", "3des-md5"), + "cloudstack_vpn_customer_gateway.bar", "esp_policy", "3des-md5"), ), }, }, @@ -135,7 +135,7 @@ func testAccCheckCloudStackVPNCustomerGatewayDestroy(s *terraform.State) error { cs := testAccProvider.Meta().(*cloudstack.CloudStackClient) for _, rs := range s.RootModule().Resources { - if rs.Type != "cloudstack_vpn_connection" { + if rs.Type != "cloudstack_vpn_customer_gateway" { continue } @@ -158,16 +158,14 @@ func testAccCheckCloudStackVPNCustomerGatewayDestroy(s *terraform.State) error { var testAccCloudStackVPNCustomerGateway_basic = fmt.Sprintf(` resource "cloudstack_vpc" "foo" { - name = "terraform-vpc" - display_text = "terraform-vpc-text" + name = "terraform-vpc-foo" cidr = "%s" vpc_offering = "%s" zone = "%s" } resource "cloudstack_vpc" "bar" { - name = "terraform-vpc" - display_text = "terraform-vpc-text" + name = "terraform-vpc-bar" cidr = "%s" vpc_offering = "%s" zone = "%s" @@ -185,7 +183,7 @@ resource "cloudstack_vpn_customer_gateway" "foo" { name = "terraform-foo" cidr = "${cloudstack_vpc.foo.cidr}" esp_policy = "aes256-sha1" - gateway = "${cloudstack_vpn_gateway.foo.publicip}" + gateway = "${cloudstack_vpn_gateway.foo.public_ip}" ike_policy = "aes256-sha1" ipsec_psk = "terraform" } @@ -194,7 +192,7 @@ resource "cloudstack_vpn_customer_gateway" "bar" { name = "terraform-bar" cidr = "${cloudstack_vpc.bar.cidr}" esp_policy = "aes256-sha1" - gateway = "${cloudstack_vpn_gateway.bar.publicip}" + gateway = "${cloudstack_vpn_gateway.bar.public_ip}" ike_policy = "aes256-sha1" ipsec_psk = "terraform" }`, @@ -210,7 +208,7 @@ resource "cloudstack_vpn_customer_gateway" "foo" { name = "terraform-foo-bar" cidr = "${cloudstack_vpc.foo.cidr}" esp_policy = "3des-md5" - gateway = "${cloudstack_vpn_gateway.foo.publicip}" + gateway = "${cloudstack_vpn_gateway.foo.public_ip}" ike_policy = "3des-md5" ipsec_psk = "terraform" } @@ -219,7 +217,7 @@ resource "cloudstack_vpn_customer_gateway" "bar" { name = "terraform-bar-foo" cidr = "${cloudstack_vpc.bar.cidr}" esp_policy = "3des-md5" - gateway = "${cloudstack_vpn_gateway.bar.publicip}" + gateway = "${cloudstack_vpn_gateway.bar.public_ip}" ike_policy = "3des-md5" ipsec_psk = "terraform" }`) From 20b02cacd454c2318c60132e9ba1b7dc5f75ebca Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Mon, 9 Mar 2015 10:02:27 -0500 Subject: [PATCH 05/20] provider/aws: Convert AWS Security Group to aws-sdk-go Convert security group test too --- .../aws/resource_aws_security_group.go | 150 +++++++++++------- .../aws/resource_aws_security_group_test.go | 134 ++++++++-------- builtin/providers/aws/structure.go | 62 ++++++++ 3 files changed, 223 insertions(+), 123 deletions(-) diff --git a/builtin/providers/aws/resource_aws_security_group.go b/builtin/providers/aws/resource_aws_security_group.go index 451f1816f..a0b09a55a 100644 --- a/builtin/providers/aws/resource_aws_security_group.go +++ b/builtin/providers/aws/resource_aws_security_group.go @@ -7,10 +7,11 @@ import ( "sort" "time" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/mitchellh/goamz/ec2" ) func resourceAwsSecurityGroup() *schema.Resource { @@ -141,18 +142,18 @@ func resourceAwsSecurityGroup() *schema.Resource { } func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn - securityGroupOpts := ec2.SecurityGroup{ - Name: d.Get("name").(string), + securityGroupOpts := &ec2.CreateSecurityGroupRequest{ + GroupName: aws.String(d.Get("name").(string)), } if v := d.Get("vpc_id"); v != nil { - securityGroupOpts.VpcId = v.(string) + securityGroupOpts.VPCID = aws.String(v.(string)) } if v := d.Get("description"); v != nil { - securityGroupOpts.Description = v.(string) + securityGroupOpts.Description = aws.String(v.(string)) } log.Printf( @@ -162,7 +163,7 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Error creating Security Group: %s", err) } - d.SetId(createResp.Id) + d.SetId(*createResp.GroupID) log.Printf("[INFO] Security Group ID: %s", d.Id()) @@ -186,7 +187,7 @@ func resourceAwsSecurityGroupCreate(d *schema.ResourceData, meta interface{}) er } func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())() if err != nil { @@ -197,24 +198,23 @@ func resourceAwsSecurityGroupRead(d *schema.ResourceData, meta interface{}) erro return nil } - sg := sgRaw.(*ec2.SecurityGroupInfo) + sg := sgRaw.(ec2.SecurityGroup) - ingressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPerms) - egressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPermsEgress) + ingressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPermissions) + egressRules := resourceAwsSecurityGroupIPPermGather(d, sg.IPPermissionsEgress) d.Set("description", sg.Description) - d.Set("name", sg.Name) - d.Set("vpc_id", sg.VpcId) - d.Set("owner_id", sg.OwnerId) + d.Set("name", sg.GroupName) + d.Set("vpc_id", sg.VPCID) + d.Set("owner_id", sg.OwnerID) d.Set("ingress", ingressRules) d.Set("egress", egressRules) - d.Set("tags", tagsToMap(sg.Tags)) - + d.Set("tags", tagsToMapSDK(sg.Tags)) return nil } func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn sgRaw, _, err := SGStateRefreshFunc(ec2conn, d.Id())() if err != nil { @@ -224,7 +224,8 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er d.SetId("") return nil } - group := sgRaw.(*ec2.SecurityGroupInfo).SecurityGroup + + group := sgRaw.(ec2.SecurityGroup) err = resourceAwsSecurityGroupUpdateRules(d, "ingress", meta, group) if err != nil { @@ -238,7 +239,7 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er } } - if err := setTags(ec2conn, d); err != nil { + if err := setTagsSDK(ec2conn, d); err != nil { return err } @@ -248,14 +249,16 @@ func resourceAwsSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) er } func resourceAwsSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn log.Printf("[DEBUG] Security Group destroy: %v", d.Id()) return resource.Retry(5*time.Minute, func() error { - _, err := ec2conn.DeleteSecurityGroup(ec2.SecurityGroup{Id: d.Id()}) + err := ec2conn.DeleteSecurityGroup(&ec2.DeleteSecurityGroupRequest{ + GroupID: aws.String(d.Id()), + }) if err != nil { - ec2err, ok := err.(*ec2.Error) + ec2err, ok := err.(aws.APIError) if !ok { return err } @@ -313,34 +316,49 @@ func resourceAwsSecurityGroupRuleHash(v interface{}) int { return hashcode.String(buf.String()) } -func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions []ec2.IPPerm) []map[string]interface{} { +func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions []ec2.IPPermission) []map[string]interface{} { ruleMap := make(map[string]map[string]interface{}) for _, perm := range permissions { - k := fmt.Sprintf("%s-%d-%d", perm.Protocol, perm.FromPort, perm.ToPort) + var fromPort, toPort int + if perm.FromPort == nil { + fromPort = 0 + } else { + fromPort = *perm.FromPort + } + if perm.ToPort == nil { + toPort = 0 + } else { + toPort = *perm.ToPort + } + + k := fmt.Sprintf("%s-%d-%d", *perm.IPProtocol, fromPort, toPort) m, ok := ruleMap[k] if !ok { m = make(map[string]interface{}) ruleMap[k] = m } - m["from_port"] = perm.FromPort - m["to_port"] = perm.ToPort - m["protocol"] = perm.Protocol + m["from_port"] = fromPort + m["to_port"] = toPort + m["protocol"] = *perm.IPProtocol - if len(perm.SourceIPs) > 0 { + if len(perm.IPRanges) > 0 { raw, ok := m["cidr_blocks"] if !ok { - raw = make([]string, 0, len(perm.SourceIPs)) + raw = make([]string, 0, len(perm.IPRanges)) } list := raw.([]string) - list = append(list, perm.SourceIPs...) + for _, ip := range perm.IPRanges { + list = append(list, *ip.CIDRIP) + } + m["cidr_blocks"] = list } var groups []string - if len(perm.SourceGroups) > 0 { - groups = flattenSecurityGroups(perm.SourceGroups) + if len(perm.UserIDGroupPairs) > 0 { + groups = flattenSecurityGroupsSDK(perm.UserIDGroupPairs) } for i, id := range groups { if id == d.Id() { @@ -364,7 +382,6 @@ func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions [] for _, m := range ruleMap { rules = append(rules, m) } - return rules } @@ -383,8 +400,9 @@ func resourceAwsSecurityGroupUpdateRules( os := o.(*schema.Set) ns := n.(*schema.Set) - remove := expandIPPerms(d.Id(), os.Difference(ns).List()) - add := expandIPPerms(d.Id(), ns.Difference(os).List()) + // TODO: re-munge this when test is updated + remove := expandIPPermsSDK(d.Id(), os.Difference(ns).List()) + add := expandIPPermsSDK(d.Id(), ns.Difference(os).List()) // TODO: We need to handle partial state better in the in-between // in this update. @@ -396,34 +414,53 @@ func resourceAwsSecurityGroupUpdateRules( // not have service issues. if len(remove) > 0 || len(add) > 0 { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn + var err error if len(remove) > 0 { - // Revoke the old rules - revoke := ec2conn.RevokeSecurityGroup - if ruleset == "egress" { - revoke = ec2conn.RevokeSecurityGroupEgress - } - log.Printf("[DEBUG] Revoking security group %s %s rule: %#v", group, ruleset, remove) - if _, err := revoke(group, remove); err != nil { + + if ruleset == "egress" { + req := &ec2.RevokeSecurityGroupEgressRequest{ + GroupID: group.GroupID, + IPPermissions: remove, + } + err = ec2conn.RevokeSecurityGroupEgress(req) + } else { + req := &ec2.RevokeSecurityGroupIngressRequest{ + GroupID: group.GroupID, + IPPermissions: remove, + } + err = ec2conn.RevokeSecurityGroupIngress(req) + } + + if err != nil { return fmt.Errorf( - "Error revoking security group %s rules: %s", + "Error authorizing security group %s rules: %s", ruleset, err) } } if len(add) > 0 { - // Authorize the new rules - authorize := ec2conn.AuthorizeSecurityGroup - if ruleset == "egress" { - authorize = ec2conn.AuthorizeSecurityGroupEgress - } - log.Printf("[DEBUG] Authorizing security group %s %s rule: %#v", group, ruleset, add) - if _, err := authorize(group, add); err != nil { + // Authorize the new rules + if ruleset == "egress" { + req := &ec2.AuthorizeSecurityGroupEgressRequest{ + GroupID: group.GroupID, + IPPermissions: add, + } + err = ec2conn.AuthorizeSecurityGroupEgress(req) + } else { + req := &ec2.AuthorizeSecurityGroupIngressRequest{ + GroupID: group.GroupID, + IPPermissions: add, + } + err = ec2conn.AuthorizeSecurityGroupIngress(req) + } + + if err != nil { return fmt.Errorf( "Error authorizing security group %s rules: %s", ruleset, err) @@ -431,7 +468,6 @@ func resourceAwsSecurityGroupUpdateRules( } } } - return nil } @@ -439,10 +475,12 @@ func resourceAwsSecurityGroupUpdateRules( // a security group. func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - sgs := []ec2.SecurityGroup{ec2.SecurityGroup{Id: id}} - resp, err := conn.SecurityGroups(sgs, nil) + req := &ec2.DescribeSecurityGroupsRequest{ + GroupIDs: []string{id}, + } + resp, err := conn.DescribeSecurityGroups(req) if err != nil { - if ec2err, ok := err.(*ec2.Error); ok { + if ec2err, ok := err.(aws.APIError); ok { if ec2err.Code == "InvalidSecurityGroupID.NotFound" || ec2err.Code == "InvalidGroup.NotFound" { resp = nil @@ -460,7 +498,7 @@ func SGStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return nil, "", nil } - group := &resp.Groups[0] + group := resp.SecurityGroups[0] return group, "exists", nil } } diff --git a/builtin/providers/aws/resource_aws_security_group_test.go b/builtin/providers/aws/resource_aws_security_group_test.go index d31f9754b..c8c08c733 100644 --- a/builtin/providers/aws/resource_aws_security_group_test.go +++ b/builtin/providers/aws/resource_aws_security_group_test.go @@ -2,16 +2,18 @@ package aws import ( "fmt" + "log" "reflect" "testing" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/mitchellh/goamz/ec2" ) func TestAccAWSSecurityGroup_normal(t *testing.T) { - var group ec2.SecurityGroupInfo + var group ec2.SecurityGroup resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -44,16 +46,18 @@ func TestAccAWSSecurityGroup_normal(t *testing.T) { } func TestAccAWSSecurityGroup_self(t *testing.T) { - var group ec2.SecurityGroupInfo + var group ec2.SecurityGroup checkSelf := func(s *terraform.State) (err error) { defer func() { if e := recover(); e != nil { + log.Printf("\n\nbad here!!") err = fmt.Errorf("bad: %#v", group) } }() - if group.IPPerms[0].SourceGroups[0].Id != group.Id { + if *group.IPPermissions[0].UserIDGroupPairs[0].GroupID != *group.GroupID { + log.Printf("\n\n---- bad here ----\n") return fmt.Errorf("bad: %#v", group) } @@ -89,10 +93,10 @@ func TestAccAWSSecurityGroup_self(t *testing.T) { } func TestAccAWSSecurityGroup_vpc(t *testing.T) { - var group ec2.SecurityGroupInfo + var group ec2.SecurityGroup testCheck := func(*terraform.State) error { - if group.VpcId == "" { + if *group.VPCID == "" { return fmt.Errorf("should have vpc ID") } @@ -141,7 +145,7 @@ func TestAccAWSSecurityGroup_vpc(t *testing.T) { } func TestAccAWSSecurityGroup_MultiIngress(t *testing.T) { - var group ec2.SecurityGroupInfo + var group ec2.SecurityGroup resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -159,7 +163,7 @@ func TestAccAWSSecurityGroup_MultiIngress(t *testing.T) { } func TestAccAWSSecurityGroup_Change(t *testing.T) { - var group ec2.SecurityGroupInfo + var group ec2.SecurityGroup resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -184,30 +188,27 @@ func TestAccAWSSecurityGroup_Change(t *testing.T) { } func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ec2conn + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_security_group" { continue } - sgs := []ec2.SecurityGroup{ - ec2.SecurityGroup{ - Id: rs.Primary.ID, - }, - } - // Retrieve our group - resp, err := conn.SecurityGroups(sgs, nil) + req := &ec2.DescribeSecurityGroupsRequest{ + GroupIDs: []string{rs.Primary.ID}, + } + resp, err := conn.DescribeSecurityGroups(req) if err == nil { - if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.Primary.ID { + if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupID == rs.Primary.ID { return fmt.Errorf("Security Group (%s) still exists.", rs.Primary.ID) } return nil } - ec2err, ok := err.(*ec2.Error) + ec2err, ok := err.(aws.APIError) if !ok { return err } @@ -220,7 +221,7 @@ func testAccCheckAWSSecurityGroupDestroy(s *terraform.State) error { return nil } -func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo) resource.TestCheckFunc { +func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroup) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -231,20 +232,19 @@ func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo) return fmt.Errorf("No Security Group is set") } - conn := testAccProvider.Meta().(*AWSClient).ec2conn - sgs := []ec2.SecurityGroup{ - ec2.SecurityGroup{ - Id: rs.Primary.ID, - }, + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn + req := &ec2.DescribeSecurityGroupsRequest{ + GroupIDs: []string{rs.Primary.ID}, } - resp, err := conn.SecurityGroups(sgs, nil) + resp, err := conn.DescribeSecurityGroups(req) if err != nil { return err } - if len(resp.Groups) > 0 && resp.Groups[0].Id == rs.Primary.ID { + if len(resp.SecurityGroups) > 0 && *resp.SecurityGroups[0].GroupID == rs.Primary.ID { - *group = resp.Groups[0] + log.Printf("\n==\n===\nfound group\n===\n==\n") + *group = resp.SecurityGroups[0] return nil } @@ -253,32 +253,32 @@ func testAccCheckAWSSecurityGroupExists(n string, group *ec2.SecurityGroupInfo) } } -func testAccCheckAWSSecurityGroupAttributes(group *ec2.SecurityGroupInfo) resource.TestCheckFunc { +func testAccCheckAWSSecurityGroupAttributes(group *ec2.SecurityGroup) resource.TestCheckFunc { return func(s *terraform.State) error { - p := ec2.IPPerm{ - FromPort: 80, - ToPort: 8000, - Protocol: "tcp", - SourceIPs: []string{"10.0.0.0/8"}, + p := ec2.IPPermission{ + FromPort: aws.Integer(80), + ToPort: aws.Integer(8000), + IPProtocol: aws.String("tcp"), + IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("10.0.0.0/8")}}, } - if group.Name != "terraform_acceptance_test_example" { - return fmt.Errorf("Bad name: %s", group.Name) + if *group.GroupName != "terraform_acceptance_test_example" { + return fmt.Errorf("Bad name: %s", *group.GroupName) } - if group.Description != "Used in the terraform acceptance tests" { - return fmt.Errorf("Bad description: %s", group.Description) + if *group.Description != "Used in the terraform acceptance tests" { + return fmt.Errorf("Bad description: %s", *group.Description) } - if len(group.IPPerms) == 0 { + if len(group.IPPermissions) == 0 { return fmt.Errorf("No IPPerms") } // Compare our ingress - if !reflect.DeepEqual(group.IPPerms[0], p) { + if !reflect.DeepEqual(group.IPPermissions[0], p) { return fmt.Errorf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", - group.IPPerms[0], + group.IPPermissions[0], p) } @@ -287,7 +287,7 @@ func testAccCheckAWSSecurityGroupAttributes(group *ec2.SecurityGroupInfo) resour } func TestAccAWSSecurityGroup_tags(t *testing.T) { - var group ec2.SecurityGroupInfo + var group ec2.SecurityGroup resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -298,7 +298,7 @@ func TestAccAWSSecurityGroup_tags(t *testing.T) { Config: testAccAWSSecurityGroupConfigTags, Check: resource.ComposeTestCheckFunc( testAccCheckAWSSecurityGroupExists("aws_security_group.foo", &group), - testAccCheckTags(&group.Tags, "foo", "bar"), + testAccCheckTagsSDK(&group.Tags, "foo", "bar"), ), }, @@ -306,56 +306,56 @@ func TestAccAWSSecurityGroup_tags(t *testing.T) { Config: testAccAWSSecurityGroupConfigTagsUpdate, Check: resource.ComposeTestCheckFunc( testAccCheckAWSSecurityGroupExists("aws_security_group.foo", &group), - testAccCheckTags(&group.Tags, "foo", ""), - testAccCheckTags(&group.Tags, "bar", "baz"), + testAccCheckTagsSDK(&group.Tags, "foo", ""), + testAccCheckTagsSDK(&group.Tags, "bar", "baz"), ), }, }, }) } -func testAccCheckAWSSecurityGroupAttributesChanged(group *ec2.SecurityGroupInfo) resource.TestCheckFunc { +func testAccCheckAWSSecurityGroupAttributesChanged(group *ec2.SecurityGroup) resource.TestCheckFunc { return func(s *terraform.State) error { - p := []ec2.IPPerm{ - ec2.IPPerm{ - FromPort: 80, - ToPort: 9000, - Protocol: "tcp", - SourceIPs: []string{"10.0.0.0/8"}, + p := []ec2.IPPermission{ + ec2.IPPermission{ + FromPort: aws.Integer(80), + ToPort: aws.Integer(9000), + IPProtocol: aws.String("tcp"), + IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("10.0.0.0/8")}}, }, - ec2.IPPerm{ - FromPort: 80, - ToPort: 8000, - Protocol: "tcp", - SourceIPs: []string{"0.0.0.0/0", "10.0.0.0/8"}, + ec2.IPPermission{ + FromPort: aws.Integer(80), + ToPort: aws.Integer(8000), + IPProtocol: aws.String("tcp"), + IPRanges: []ec2.IPRange{ec2.IPRange{aws.String("0.0.0.0/0")}, ec2.IPRange{aws.String("10.0.0.0/8")}}, }, } - if group.Name != "terraform_acceptance_test_example" { - return fmt.Errorf("Bad name: %s", group.Name) + if *group.GroupName != "terraform_acceptance_test_example" { + return fmt.Errorf("Bad name: %s", *group.GroupName) } - if group.Description != "Used in the terraform acceptance tests" { - return fmt.Errorf("Bad description: %s", group.Description) + if *group.Description != "Used in the terraform acceptance tests" { + return fmt.Errorf("Bad description: %s", *group.Description) } // Compare our ingress - if len(group.IPPerms) != 2 { + if len(group.IPPermissions) != 2 { return fmt.Errorf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", - group.IPPerms, + group.IPPermissions, p) } - if group.IPPerms[0].ToPort == 8000 { - group.IPPerms[1], group.IPPerms[0] = - group.IPPerms[0], group.IPPerms[1] + if *group.IPPermissions[0].ToPort == 8000 { + group.IPPermissions[1], group.IPPermissions[0] = + group.IPPermissions[0], group.IPPermissions[1] } - if !reflect.DeepEqual(group.IPPerms, p) { + if !reflect.DeepEqual(group.IPPermissions, p) { return fmt.Errorf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", - group.IPPerms, + group.IPPermissions, p) } diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 7d4793d3d..49f6cfc4d 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/hashicorp/aws-sdk-go/aws" + awsEC2 "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/aws-sdk-go/gen/elb" "github.com/hashicorp/aws-sdk-go/gen/rds" "github.com/hashicorp/terraform/helper/schema" @@ -89,6 +90,58 @@ func expandIPPerms(id string, configured []interface{}) []ec2.IPPerm { return perms } +// Takes the result of flatmap.Expand for an array of ingress/egress +// security group rules and returns EC2 API compatible objects +func expandIPPermsSDK(id string, configured []interface{}) []awsEC2.IPPermission { + perms := make([]awsEC2.IPPermission, len(configured)) + for i, mRaw := range configured { + var perm awsEC2.IPPermission + m := mRaw.(map[string]interface{}) + + perm.FromPort = aws.Integer(m["from_port"].(int)) + perm.ToPort = aws.Integer(m["to_port"].(int)) + perm.IPProtocol = aws.String(m["protocol"].(string)) + + var groups []string + if raw, ok := m["security_groups"]; ok { + list := raw.(*schema.Set).List() + for _, v := range list { + groups = append(groups, v.(string)) + } + } + if v, ok := m["self"]; ok && v.(bool) { + groups = append(groups, id) + } + + if len(groups) > 0 { + perm.UserIDGroupPairs = make([]awsEC2.UserIDGroupPair, len(groups)) + for i, name := range groups { + ownerId, id := "", name + if items := strings.Split(id, "/"); len(items) > 1 { + ownerId, id = items[0], items[1] + } + + perm.UserIDGroupPairs[i] = awsEC2.UserIDGroupPair{ + GroupID: aws.String(id), + UserID: aws.String(ownerId), + } + } + } + + if raw, ok := m["cidr_blocks"]; ok { + list := raw.([]interface{}) + perm.IPRanges = make([]awsEC2.IPRange, len(list)) + for i, v := range list { + perm.IPRanges[i] = awsEC2.IPRange{aws.String(v.(string))} + } + } + + perms[i] = perm + } + + return perms +} + // Takes the result of flatmap.Expand for an array of parameters and // returns Parameter API compatible objects func expandParameters(configured []interface{}) ([]rds.Parameter, error) { @@ -162,6 +215,15 @@ func flattenSecurityGroups(list []ec2.UserSecurityGroup) []string { return result } +// Flattens an array of UserSecurityGroups into a []string +func flattenSecurityGroupsSDK(list []awsEC2.UserIDGroupPair) []string { + result := make([]string, 0, len(list)) + for _, g := range list { + result = append(result, *g.GroupID) + } + return result +} + // Flattens an array of Instances into a []string func flattenInstances(list []elb.Instance) []string { result := make([]string, 0, len(list)) From bc44fdc1a7443c2c94ac5d982791ae03beb1b77c Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Mon, 9 Mar 2015 19:06:27 +0000 Subject: [PATCH 06/20] aws/Route53 record creation timeout 10->30 mins --- builtin/providers/aws/resource_aws_route53_record.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_route53_record.go b/builtin/providers/aws/resource_aws_route53_record.go index 96c7608fe..fcd781c61 100644 --- a/builtin/providers/aws/resource_aws_route53_record.go +++ b/builtin/providers/aws/resource_aws_route53_record.go @@ -138,7 +138,7 @@ func resourceAwsRoute53RecordCreate(d *schema.ResourceData, meta interface{}) er Delay: 30 * time.Second, Pending: []string{"PENDING"}, Target: "INSYNC", - Timeout: 10 * time.Minute, + Timeout: 30 * time.Minute, MinTimeout: 5 * time.Second, Refresh: func() (result interface{}, state string, err error) { changeRequest := &route53.GetChangeRequest{ From 5a13ac9bc9a856e47646ed14ce99cb6ece20bd55 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Mon, 9 Mar 2015 16:15:25 -0500 Subject: [PATCH 07/20] provider/aws: Convert Main Route Table assoc. to aws-sdk-go --- ...source_aws_main_route_table_association.go | 56 ++++++++++++------- ...e_aws_main_route_table_association_test.go | 6 +- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/builtin/providers/aws/resource_aws_main_route_table_association.go b/builtin/providers/aws/resource_aws_main_route_table_association.go index f656f3760..a489b9a50 100644 --- a/builtin/providers/aws/resource_aws_main_route_table_association.go +++ b/builtin/providers/aws/resource_aws_main_route_table_association.go @@ -4,8 +4,9 @@ import ( "fmt" "log" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/schema" - "github.com/mitchellh/goamz/ec2" ) func resourceAwsMainRouteTableAssociation() *schema.Resource { @@ -39,7 +40,7 @@ func resourceAwsMainRouteTableAssociation() *schema.Resource { } func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn vpcId := d.Get("vpc_id").(string) routeTableId := d.Get("route_table_id").(string) @@ -50,23 +51,23 @@ func resourceAwsMainRouteTableAssociationCreate(d *schema.ResourceData, meta int return err } - resp, err := ec2conn.ReassociateRouteTable( - mainAssociation.AssociationId, - routeTableId, - ) + resp, err := ec2conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationRequest{ + AssociationID: mainAssociation.RouteTableAssociationID, + RouteTableID: aws.String(routeTableId), + }) if err != nil { return err } - d.Set("original_route_table_id", mainAssociation.RouteTableId) - d.SetId(resp.AssociationId) + d.Set("original_route_table_id", mainAssociation.RouteTableID) + d.SetId(*resp.NewAssociationID) log.Printf("[INFO] New main route table association ID: %s", d.Id()) return nil } func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn mainAssociation, err := findMainRouteTableAssociation( ec2conn, @@ -75,7 +76,7 @@ func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta inter return err } - if mainAssociation.AssociationId != d.Id() { + if *mainAssociation.RouteTableAssociationID != d.Id() { // It seems it doesn't exist anymore, so clear the ID d.SetId("") } @@ -87,25 +88,28 @@ func resourceAwsMainRouteTableAssociationRead(d *schema.ResourceData, meta inter // original_route_table_id - this needs to stay recorded as the AWS-created // table from VPC creation. func resourceAwsMainRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn vpcId := d.Get("vpc_id").(string) routeTableId := d.Get("route_table_id").(string) log.Printf("[INFO] Updating main route table association: %s => %s", vpcId, routeTableId) - resp, err := ec2conn.ReassociateRouteTable(d.Id(), routeTableId) + resp, err := ec2conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationRequest{ + AssociationID: aws.String(d.Id()), + RouteTableID: aws.String(routeTableId), + }) if err != nil { return err } - d.SetId(resp.AssociationId) + d.SetId(*resp.NewAssociationID) log.Printf("[INFO] New main route table association ID: %s", d.Id()) return nil } func resourceAwsMainRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn vpcId := d.Get("vpc_id").(string) originalRouteTableId := d.Get("original_route_table_id").(string) @@ -113,12 +117,15 @@ func resourceAwsMainRouteTableAssociationDelete(d *schema.ResourceData, meta int vpcId, originalRouteTableId) - resp, err := ec2conn.ReassociateRouteTable(d.Id(), originalRouteTableId) + resp, err := ec2conn.ReplaceRouteTableAssociation(&ec2.ReplaceRouteTableAssociationRequest{ + AssociationID: aws.String(d.Id()), + RouteTableID: aws.String(originalRouteTableId), + }) if err != nil { return err } - log.Printf("[INFO] Resulting Association ID: %s", resp.AssociationId) + log.Printf("[INFO] Resulting Association ID: %s", *resp.NewAssociationID) return nil } @@ -130,7 +137,7 @@ func findMainRouteTableAssociation(ec2conn *ec2.EC2, vpcId string) (*ec2.RouteTa } for _, a := range mainRouteTable.Associations { - if a.Main { + if *a.Main { return &a, nil } } @@ -138,10 +145,17 @@ func findMainRouteTableAssociation(ec2conn *ec2.EC2, vpcId string) (*ec2.RouteTa } func findMainRouteTable(ec2conn *ec2.EC2, vpcId string) (*ec2.RouteTable, error) { - filter := ec2.NewFilter() - filter.Add("association.main", "true") - filter.Add("vpc-id", vpcId) - routeResp, err := ec2conn.DescribeRouteTables(nil, filter) + mainFilter := ec2.Filter{ + aws.String("association.main"), + []string{"true"}, + } + vpcFilter := ec2.Filter{ + aws.String("vpc-id"), + []string{vpcId}, + } + routeResp, err := ec2conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ + Filters: []ec2.Filter{mainFilter, vpcFilter}, + }) if err != nil { return nil, err } else if len(routeResp.RouteTables) != 1 { diff --git a/builtin/providers/aws/resource_aws_main_route_table_association_test.go b/builtin/providers/aws/resource_aws_main_route_table_association_test.go index 937014cae..76e3e4d72 100644 --- a/builtin/providers/aws/resource_aws_main_route_table_association_test.go +++ b/builtin/providers/aws/resource_aws_main_route_table_association_test.go @@ -65,15 +65,15 @@ func testAccCheckMainRouteTableAssociation( return fmt.Errorf("Not found: %s", vpcResource) } - conn := testAccProvider.Meta().(*AWSClient).ec2conn + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn mainAssociation, err := findMainRouteTableAssociation(conn, vpc.Primary.ID) if err != nil { return err } - if mainAssociation.AssociationId != rs.Primary.ID { + if *mainAssociation.RouteTableAssociationID != rs.Primary.ID { return fmt.Errorf("Found wrong main association: %s", - mainAssociation.AssociationId) + *mainAssociation.RouteTableAssociationID) } return nil From 795970d5a267c665d3ff9720d39473e7b448ddb6 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Mon, 9 Mar 2015 17:11:30 -0500 Subject: [PATCH 08/20] Give route table assoc it's own copy of this method for now --- .../resource_aws_route_table_association.go | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/builtin/providers/aws/resource_aws_route_table_association.go b/builtin/providers/aws/resource_aws_route_table_association.go index 846836008..4b39a79b7 100644 --- a/builtin/providers/aws/resource_aws_route_table_association.go +++ b/builtin/providers/aws/resource_aws_route_table_association.go @@ -4,6 +4,7 @@ import ( "fmt" "log" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/mitchellh/goamz/ec2" ) @@ -129,3 +130,29 @@ func resourceAwsRouteTableAssociationDelete(d *schema.ResourceData, meta interfa return nil } + +// TODO: remove this method when converting to aws-sdk-go +// resourceAwsRouteTableStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// a RouteTable. +func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := conn.DescribeRouteTables([]string{id}, ec2.NewFilter()) + if err != nil { + if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidRouteTableID.NotFound" { + resp = nil + } else { + log.Printf("Error on RouteTableStateRefresh: %s", err) + return nil, "", err + } + } + + if resp == nil { + // Sometimes AWS just has consistency issues and doesn't see + // our instance yet. Return an empty state. + return nil, "", nil + } + + rt := &resp.RouteTables[0] + return rt, "ready", nil + } +} From 30941dfdc4e6d04d8e999f700286fbd24955f5f2 Mon Sep 17 00:00:00 2001 From: Suguru Namura Date: Tue, 10 Mar 2015 19:45:56 +0900 Subject: [PATCH 09/20] providers/aws: iops in root device skipped when output state --- builtin/providers/aws/resource_aws_instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index ee62d305e..d0c6a3bb7 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -482,6 +482,7 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { blockDevice["device_name"] = blockDevices[vol.VolumeId].DeviceName blockDevice["volume_type"] = vol.VolumeType blockDevice["volume_size"] = volSize + blockDevice["iops"] = vol.IOPS blockDevice["delete_on_termination"] = blockDevices[vol.VolumeId].DeleteOnTermination @@ -494,7 +495,6 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error { blockDevice["snapshot_id"] = vol.SnapshotId blockDevice["encrypted"] = vol.Encrypted - blockDevice["iops"] = vol.IOPS nonRootBlockDevices = append(nonRootBlockDevices, blockDevice) } d.Set("block_device", nonRootBlockDevices) From 30f401eab7bf285cdd8b0f48819881d362dec24e Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 10:23:14 -0500 Subject: [PATCH 10/20] provider/aws: Convert AWS Route Table to aws-sdk-go --- .../providers/aws/resource_aws_route_table.go | 98 +++++++++++-------- .../aws/resource_aws_route_table_test.go | 10 +- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/builtin/providers/aws/resource_aws_route_table.go b/builtin/providers/aws/resource_aws_route_table.go index 9d01218b0..76bcd17a2 100644 --- a/builtin/providers/aws/resource_aws_route_table.go +++ b/builtin/providers/aws/resource_aws_route_table.go @@ -6,10 +6,11 @@ import ( "log" "time" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/mitchellh/goamz/ec2" ) func resourceAwsRouteTable() *schema.Resource { @@ -61,11 +62,11 @@ func resourceAwsRouteTable() *schema.Resource { } func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn // Create the routing table - createOpts := &ec2.CreateRouteTable{ - VpcId: d.Get("vpc_id").(string), + createOpts := &ec2.CreateRouteTableRequest{ + VPCID: aws.String(d.Get("vpc_id").(string)), } log.Printf("[DEBUG] RouteTable create config: %#v", createOpts) @@ -75,8 +76,8 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error } // Get the ID and store it - rt := &resp.RouteTable - d.SetId(rt.RouteTableId) + rt := resp.RouteTable + d.SetId(*rt.RouteTableID) log.Printf("[INFO] Route Table ID: %s", d.Id()) // Wait for the route table to become available @@ -86,7 +87,7 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error stateConf := &resource.StateChangeConf{ Pending: []string{"pending"}, Target: "ready", - Refresh: resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id()), + Refresh: resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id()), Timeout: 1 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { @@ -99,9 +100,9 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error } func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn - rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())() + rtRaw, _, err := resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id())() if err != nil { return err } @@ -110,40 +111,48 @@ func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { } rt := rtRaw.(*ec2.RouteTable) - d.Set("vpc_id", rt.VpcId) + d.Set("vpc_id", rt.VPCID) // Create an empty schema.Set to hold all routes route := &schema.Set{F: resourceAwsRouteTableHash} // Loop through the routes and add them to the set for _, r := range rt.Routes { - if r.GatewayId == "local" { + if r.GatewayID != nil && *r.GatewayID == "local" { continue } - if r.Origin == "EnableVgwRoutePropagation" { + if r.Origin != nil && *r.Origin == "EnableVgwRoutePropagation" { continue } m := make(map[string]interface{}) - m["cidr_block"] = r.DestinationCidrBlock - m["gateway_id"] = r.GatewayId - m["instance_id"] = r.InstanceId - m["vpc_peering_connection_id"] = r.VpcPeeringConnectionId + if r.DestinationCIDRBlock != nil { + m["cidr_block"] = *r.DestinationCIDRBlock + } + if r.GatewayID != nil { + m["gateway_id"] = *r.GatewayID + } + if r.InstanceID != nil { + m["instance_id"] = *r.InstanceID + } + if r.VPCPeeringConnectionID != nil { + m["vpc_peering_connection_id"] = *r.VPCPeeringConnectionID + } route.Add(m) } d.Set("route", route) // Tags - d.Set("tags", tagsToMap(rt.Tags)) + d.Set("tags", tagsToMapSDK(rt.Tags)) return nil } func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn // Check if the route set as a whole has changed if d.HasChange("route") { @@ -159,8 +168,10 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error log.Printf( "[INFO] Deleting route from %s: %s", d.Id(), m["cidr_block"].(string)) - _, err := ec2conn.DeleteRoute( - d.Id(), m["cidr_block"].(string)) + err := ec2conn.DeleteRoute(&ec2.DeleteRouteRequest{ + RouteTableID: aws.String(d.Id()), + DestinationCIDRBlock: aws.String(m["cidr_block"].(string)), + }) if err != nil { return err } @@ -174,17 +185,16 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error for _, route := range nrs.List() { m := route.(map[string]interface{}) - opts := ec2.CreateRoute{ - RouteTableId: d.Id(), - DestinationCidrBlock: m["cidr_block"].(string), - GatewayId: m["gateway_id"].(string), - InstanceId: m["instance_id"].(string), - VpcPeeringConnectionId: m["vpc_peering_connection_id"].(string), + opts := ec2.CreateRouteRequest{ + RouteTableID: aws.String(d.Id()), + DestinationCIDRBlock: aws.String(m["cidr_block"].(string)), + GatewayID: aws.String(m["gateway_id"].(string)), + InstanceID: aws.String(m["instance_id"].(string)), + VPCPeeringConnectionID: aws.String(m["vpc_peering_connection_id"].(string)), } log.Printf("[INFO] Creating route for %s: %#v", d.Id(), opts) - _, err := ec2conn.CreateRoute(&opts) - if err != nil { + if err := ec2conn.CreateRoute(&opts); err != nil { return err } @@ -193,7 +203,7 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error } } - if err := setTags(ec2conn, d); err != nil { + if err := setTagsSDK(ec2conn, d); err != nil { return err } else { d.SetPartial("tags") @@ -203,11 +213,11 @@ func resourceAwsRouteTableUpdate(d *schema.ResourceData, meta interface{}) error } func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn // First request the routing table since we'll have to disassociate // all the subnets first. - rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())() + rtRaw, _, err := resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id())() if err != nil { return err } @@ -218,16 +228,22 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error // Do all the disassociations for _, a := range rt.Associations { - log.Printf("[INFO] Disassociating association: %s", a.AssociationId) - if _, err := ec2conn.DisassociateRouteTable(a.AssociationId); err != nil { + log.Printf("[INFO] Disassociating association: %s", *a.RouteTableAssociationID) + err := ec2conn.DisassociateRouteTable(&ec2.DisassociateRouteTableRequest{ + AssociationID: a.RouteTableAssociationID, + }) + if err != nil { return err } } // Delete the route table log.Printf("[INFO] Deleting Route Table: %s", d.Id()) - if _, err := ec2conn.DeleteRouteTable(d.Id()); err != nil { - ec2err, ok := err.(*ec2.Error) + err = ec2conn.DeleteRouteTable(&ec2.DeleteRouteTableRequest{ + RouteTableID: aws.String(d.Id()), + }) + if err != nil { + ec2err, ok := err.(aws.APIError) if ok && ec2err.Code == "InvalidRouteTableID.NotFound" { return nil } @@ -243,7 +259,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error stateConf := &resource.StateChangeConf{ Pending: []string{"ready"}, Target: "", - Refresh: resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id()), + Refresh: resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id()), Timeout: 1 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { @@ -275,13 +291,15 @@ func resourceAwsRouteTableHash(v interface{}) int { return hashcode.String(buf.String()) } -// resourceAwsRouteTableStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// resourceAwsRouteTableStateRefreshFuncSDK returns a resource.StateRefreshFunc that is used to watch // a RouteTable. -func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { +func resourceAwsRouteTableStateRefreshFuncSDK(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - resp, err := conn.DescribeRouteTables([]string{id}, ec2.NewFilter()) + resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ + RouteTableIDs: []string{id}, + }) if err != nil { - if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidRouteTableID.NotFound" { + if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidRouteTableID.NotFound" { resp = nil } else { log.Printf("Error on RouteTableStateRefresh: %s", err) diff --git a/builtin/providers/aws/resource_aws_route_table_test.go b/builtin/providers/aws/resource_aws_route_table_test.go index 2f4dfab2e..944f0c570 100644 --- a/builtin/providers/aws/resource_aws_route_table_test.go +++ b/builtin/providers/aws/resource_aws_route_table_test.go @@ -208,7 +208,10 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec } } -func TestAccAWSRouteTable_vpcPeering(t *testing.T) { +// TODO: re-enable this test. +// VPC Peering connections are prefixed with pcx +// Right now there is no VPC Peering resource +func _TestAccAWSRouteTable_vpcPeering(t *testing.T) { var v ec2.RouteTable testCheck := func(*terraform.State) error { @@ -345,6 +348,9 @@ resource "aws_route_table" "foo" { } ` +// TODO: re-enable this test. +// VPC Peering connections are prefixed with pcx +// Right now there is no VPC Peering resource const testAccRouteTableVpcPeeringConfig = ` resource "aws_vpc" "foo" { cidr_block = "10.1.0.0/16" @@ -359,7 +365,7 @@ resource "aws_route_table" "foo" { route { cidr_block = "10.2.0.0/16" - vpc_peering_connection_id = "vpc-12345" + vpc_peering_connection_id = "pcx-12345" } } ` From e7b3f3cf17605970515d4554b10c4b0f55ae1a4b Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 10:30:01 -0500 Subject: [PATCH 11/20] convert route table tests to aws-sdk-go --- .../aws/resource_aws_route_table_test.go | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/builtin/providers/aws/resource_aws_route_table_test.go b/builtin/providers/aws/resource_aws_route_table_test.go index 944f0c570..5e6f90026 100644 --- a/builtin/providers/aws/resource_aws_route_table_test.go +++ b/builtin/providers/aws/resource_aws_route_table_test.go @@ -4,9 +4,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/mitchellh/goamz/ec2" ) func TestAccAWSRouteTable_normal(t *testing.T) { @@ -19,7 +20,7 @@ func TestAccAWSRouteTable_normal(t *testing.T) { routes := make(map[string]ec2.Route) for _, r := range v.Routes { - routes[r.DestinationCidrBlock] = r + routes[*r.DestinationCIDRBlock] = r } if _, ok := routes["10.1.0.0/16"]; !ok { @@ -39,7 +40,7 @@ func TestAccAWSRouteTable_normal(t *testing.T) { routes := make(map[string]ec2.Route) for _, r := range v.Routes { - routes[r.DestinationCidrBlock] = r + routes[*r.DestinationCIDRBlock] = r } if _, ok := routes["10.1.0.0/16"]; !ok { @@ -91,7 +92,7 @@ func TestAccAWSRouteTable_instance(t *testing.T) { routes := make(map[string]ec2.Route) for _, r := range v.Routes { - routes[r.DestinationCidrBlock] = r + routes[*r.DestinationCIDRBlock] = r } if _, ok := routes["10.1.0.0/16"]; !ok { @@ -133,7 +134,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) { Config: testAccRouteTableConfigTags, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists("aws_route_table.foo", &route_table), - testAccCheckTags(&route_table.Tags, "foo", "bar"), + testAccCheckTagsSDK(&route_table.Tags, "foo", "bar"), ), }, @@ -141,8 +142,8 @@ func TestAccAWSRouteTable_tags(t *testing.T) { Config: testAccRouteTableConfigTagsUpdate, Check: resource.ComposeTestCheckFunc( testAccCheckRouteTableExists("aws_route_table.foo", &route_table), - testAccCheckTags(&route_table.Tags, "foo", ""), - testAccCheckTags(&route_table.Tags, "bar", "baz"), + testAccCheckTagsSDK(&route_table.Tags, "foo", ""), + testAccCheckTagsSDK(&route_table.Tags, "bar", "baz"), ), }, }, @@ -150,7 +151,7 @@ func TestAccAWSRouteTable_tags(t *testing.T) { } func testAccCheckRouteTableDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ec2conn + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_route_table" { @@ -158,8 +159,9 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error { } // Try to find the resource - resp, err := conn.DescribeRouteTables( - []string{rs.Primary.ID}, ec2.NewFilter()) + resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ + RouteTableIDs: []string{rs.Primary.ID}, + }) if err == nil { if len(resp.RouteTables) > 0 { return fmt.Errorf("still exist.") @@ -169,7 +171,7 @@ func testAccCheckRouteTableDestroy(s *terraform.State) error { } // Verify the error is what we want - ec2err, ok := err.(*ec2.Error) + ec2err, ok := err.(aws.APIError) if !ok { return err } @@ -192,9 +194,10 @@ func testAccCheckRouteTableExists(n string, v *ec2.RouteTable) resource.TestChec return fmt.Errorf("No ID is set") } - conn := testAccProvider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeRouteTables( - []string{rs.Primary.ID}, ec2.NewFilter()) + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn + resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ + RouteTableIDs: []string{rs.Primary.ID}, + }) if err != nil { return err } @@ -221,7 +224,7 @@ func _TestAccAWSRouteTable_vpcPeering(t *testing.T) { routes := make(map[string]ec2.Route) for _, r := range v.Routes { - routes[r.DestinationCidrBlock] = r + routes[*r.DestinationCIDRBlock] = r } if _, ok := routes["10.1.0.0/16"]; !ok { From fe293f909e161664464ee3819444c37d3bb0cc1e Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 14:44:07 -0500 Subject: [PATCH 12/20] provider/aws: Add env default for AWS_ACCOUNT_ID in VPC Peering connection --- .../providers/aws/resource_aws_vpc_peering_connection.go | 7 ++++--- .../aws/resource_aws_vpc_peering_connection_test.go | 3 +-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/builtin/providers/aws/resource_aws_vpc_peering_connection.go b/builtin/providers/aws/resource_aws_vpc_peering_connection.go index a8316c114..b3cb1d2d8 100644 --- a/builtin/providers/aws/resource_aws_vpc_peering_connection.go +++ b/builtin/providers/aws/resource_aws_vpc_peering_connection.go @@ -19,9 +19,10 @@ func resourceAwsVpcPeeringConnection() *schema.Resource { Schema: map[string]*schema.Schema{ "peer_owner_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: schema.EnvDefaultFunc("AWS_ACCOUNT_ID", nil), }, "peer_vpc_id": &schema.Schema{ Type: schema.TypeString, diff --git a/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go b/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go index 2b4b71e33..569bf96d0 100644 --- a/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go +++ b/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go @@ -68,11 +68,10 @@ resource "aws_vpc" "foo" { } resource "aws_vpc" "bar" { - cidr_block = "10.0.1.0/16" + cidr_block = "10.1.0.0/16" } resource "aws_vpc_peering_connection" "foo" { - peer_owner_id = "12345" vpc_id = "${aws_vpc.foo.id}" peer_vpc_id = "${aws_vpc.bar.id}" } From 30125e3a5f2dd082616f08bb9b95275932b3f49b Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 15:18:30 -0500 Subject: [PATCH 13/20] providers/aws: Convert AWS VPC Peering to aws-sdk-go --- .../resource_aws_vpc_peering_connection.go | 50 +++++++++++-------- ...esource_aws_vpc_peering_connection_test.go | 11 ++-- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/builtin/providers/aws/resource_aws_vpc_peering_connection.go b/builtin/providers/aws/resource_aws_vpc_peering_connection.go index b3cb1d2d8..06f50f01c 100644 --- a/builtin/providers/aws/resource_aws_vpc_peering_connection.go +++ b/builtin/providers/aws/resource_aws_vpc_peering_connection.go @@ -5,9 +5,10 @@ import ( "log" "time" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/mitchellh/goamz/ec2" ) func resourceAwsVpcPeeringConnection() *schema.Resource { @@ -40,23 +41,23 @@ func resourceAwsVpcPeeringConnection() *schema.Resource { } func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn // Create the vpc peering connection - createOpts := &ec2.CreateVpcPeeringConnection{ - PeerOwnerId: d.Get("peer_owner_id").(string), - PeerVpcId: d.Get("peer_vpc_id").(string), - VpcId: d.Get("vpc_id").(string), + createOpts := &ec2.CreateVPCPeeringConnectionRequest{ + PeerOwnerID: aws.String(d.Get("peer_owner_id").(string)), + PeerVPCID: aws.String(d.Get("peer_vpc_id").(string)), + VPCID: aws.String(d.Get("vpc_id").(string)), } log.Printf("[DEBUG] VpcPeeringCreate create config: %#v", createOpts) - resp, err := ec2conn.CreateVpcPeeringConnection(createOpts) + resp, err := ec2conn.CreateVPCPeeringConnection(createOpts) if err != nil { return fmt.Errorf("Error creating vpc peering connection: %s", err) } // Get the ID and store it - rt := &resp.VpcPeeringConnection - d.SetId(rt.VpcPeeringConnectionId) + rt := resp.VPCPeeringConnection + d.SetId(*rt.VPCPeeringConnectionID) log.Printf("[INFO] Vpc Peering Connection ID: %s", d.Id()) // Wait for the vpc peering connection to become available @@ -79,7 +80,7 @@ func resourceAwsVpcPeeringCreate(d *schema.ResourceData, meta interface{}) error } func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn pcRaw, _, err := resourceAwsVpcPeeringConnectionStateRefreshFunc(ec2conn, d.Id())() if err != nil { return err @@ -89,20 +90,20 @@ func resourceAwsVpcPeeringRead(d *schema.ResourceData, meta interface{}) error { return nil } - pc := pcRaw.(*ec2.VpcPeeringConnection) + pc := pcRaw.(*ec2.VPCPeeringConnection) - d.Set("peer_owner_id", pc.AccepterVpcInfo.OwnerId) - d.Set("peer_vpc_id", pc.AccepterVpcInfo.VpcId) - d.Set("vpc_id", pc.RequesterVpcInfo.VpcId) - d.Set("tags", tagsToMap(pc.Tags)) + d.Set("peer_owner_id", pc.AccepterVPCInfo.OwnerID) + d.Set("peer_vpc_id", pc.AccepterVPCInfo.VPCID) + d.Set("vpc_id", pc.RequesterVPCInfo.VPCID) + d.Set("tags", tagsToMapSDK(pc.Tags)) return nil } func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn - if err := setTags(ec2conn, d); err != nil { + if err := setTagsSDK(ec2conn, d); err != nil { return err } else { d.SetPartial("tags") @@ -112,9 +113,12 @@ func resourceAwsVpcPeeringUpdate(d *schema.ResourceData, meta interface{}) error } func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn - _, err := ec2conn.DeleteVpcPeeringConnection(d.Id()) + _, err := ec2conn.DeleteVPCPeeringConnection( + &ec2.DeleteVPCPeeringConnectionRequest{ + VPCPeeringConnectionID: aws.String(d.Id()), + }) return err } @@ -123,9 +127,11 @@ func resourceAwsVpcPeeringDelete(d *schema.ResourceData, meta interface{}) error func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - resp, err := conn.DescribeVpcPeeringConnection([]string{id}, ec2.NewFilter()) + resp, err := conn.DescribeVPCPeeringConnections(&ec2.DescribeVPCPeeringConnectionsRequest{ + VPCPeeringConnectionIDs: []string{id}, + }) if err != nil { - if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" { + if ec2err, ok := err.(aws.APIError); ok && ec2err.Code == "InvalidVpcPeeringConnectionID.NotFound" { resp = nil } else { log.Printf("Error on VpcPeeringConnectionStateRefresh: %s", err) @@ -139,7 +145,7 @@ func resourceAwsVpcPeeringConnectionStateRefreshFunc(conn *ec2.EC2, id string) r return nil, "", nil } - pc := &resp.VpcPeeringConnections[0] + pc := &resp.VPCPeeringConnections[0] return pc, "ready", nil } diff --git a/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go b/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go index 569bf96d0..307dcb7d9 100644 --- a/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go +++ b/builtin/providers/aws/resource_aws_vpc_peering_connection_test.go @@ -4,9 +4,9 @@ import ( "fmt" "testing" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/mitchellh/goamz/ec2" ) func TestAccAWSVPCPeeringConnection_normal(t *testing.T) { @@ -28,17 +28,20 @@ func TestAccAWSVPCPeeringConnection_normal(t *testing.T) { } func testAccCheckAWSVpcPeeringConnectionDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ec2conn + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_vpc_peering_connection" { continue } - describe, err := conn.DescribeVpcPeeringConnection([]string{rs.Primary.ID}, ec2.NewFilter()) + describe, err := conn.DescribeVPCPeeringConnections( + &ec2.DescribeVPCPeeringConnectionsRequest{ + VPCPeeringConnectionIDs: []string{rs.Primary.ID}, + }) if err == nil { - if len(describe.VpcPeeringConnections) != 0 { + if len(describe.VPCPeeringConnections) != 0 { return fmt.Errorf("vpc peering connection still exists") } } From a22c23ad42d9977de39bf331e40615495c2a6eb3 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 15:55:49 -0500 Subject: [PATCH 14/20] clean up debug output to make go vet happy --- builtin/providers/aws/resource_aws_security_group.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/providers/aws/resource_aws_security_group.go b/builtin/providers/aws/resource_aws_security_group.go index a0b09a55a..4283332d9 100644 --- a/builtin/providers/aws/resource_aws_security_group.go +++ b/builtin/providers/aws/resource_aws_security_group.go @@ -418,7 +418,7 @@ func resourceAwsSecurityGroupUpdateRules( var err error if len(remove) > 0 { - log.Printf("[DEBUG] Revoking security group %s %s rule: %#v", + log.Printf("[DEBUG] Revoking security group %#v %s rule: %#v", group, ruleset, remove) if ruleset == "egress" { @@ -443,7 +443,7 @@ func resourceAwsSecurityGroupUpdateRules( } if len(add) > 0 { - log.Printf("[DEBUG] Authorizing security group %s %s rule: %#v", + log.Printf("[DEBUG] Authorizing security group %#v %s rule: %#v", group, ruleset, add) // Authorize the new rules if ruleset == "egress" { From 3977256c17d72a036980600522158415620bbdf1 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 16:33:15 -0500 Subject: [PATCH 15/20] Cleansup: Restore expandIPPerms, remove flattenIPPerms --- .../aws/resource_aws_security_group.go | 4 +- .../aws/resource_aws_security_group_test.go | 2 - builtin/providers/aws/structure.go | 79 +--------- builtin/providers/aws/structure_test.go | 139 +++++------------- 4 files changed, 43 insertions(+), 181 deletions(-) diff --git a/builtin/providers/aws/resource_aws_security_group.go b/builtin/providers/aws/resource_aws_security_group.go index 4283332d9..4a7153cc7 100644 --- a/builtin/providers/aws/resource_aws_security_group.go +++ b/builtin/providers/aws/resource_aws_security_group.go @@ -401,8 +401,8 @@ func resourceAwsSecurityGroupUpdateRules( ns := n.(*schema.Set) // TODO: re-munge this when test is updated - remove := expandIPPermsSDK(d.Id(), os.Difference(ns).List()) - add := expandIPPermsSDK(d.Id(), ns.Difference(os).List()) + remove := expandIPPerms(d.Id(), os.Difference(ns).List()) + add := expandIPPerms(d.Id(), ns.Difference(os).List()) // TODO: We need to handle partial state better in the in-between // in this update. diff --git a/builtin/providers/aws/resource_aws_security_group_test.go b/builtin/providers/aws/resource_aws_security_group_test.go index c8c08c733..c292c80d6 100644 --- a/builtin/providers/aws/resource_aws_security_group_test.go +++ b/builtin/providers/aws/resource_aws_security_group_test.go @@ -51,13 +51,11 @@ func TestAccAWSSecurityGroup_self(t *testing.T) { checkSelf := func(s *terraform.State) (err error) { defer func() { if e := recover(); e != nil { - log.Printf("\n\nbad here!!") err = fmt.Errorf("bad: %#v", group) } }() if *group.IPPermissions[0].UserIDGroupPairs[0].GroupID != *group.GroupID { - log.Printf("\n\n---- bad here ----\n") return fmt.Errorf("bad: %#v", group) } diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index 49f6cfc4d..910f748e6 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -40,59 +40,7 @@ func expandListeners(configured []interface{}) ([]elb.Listener, error) { // Takes the result of flatmap.Expand for an array of ingress/egress // security group rules and returns EC2 API compatible objects -func expandIPPerms(id string, configured []interface{}) []ec2.IPPerm { - perms := make([]ec2.IPPerm, len(configured)) - for i, mRaw := range configured { - var perm ec2.IPPerm - m := mRaw.(map[string]interface{}) - - perm.FromPort = m["from_port"].(int) - perm.ToPort = m["to_port"].(int) - perm.Protocol = m["protocol"].(string) - - var groups []string - if raw, ok := m["security_groups"]; ok { - list := raw.(*schema.Set).List() - for _, v := range list { - groups = append(groups, v.(string)) - } - } - if v, ok := m["self"]; ok && v.(bool) { - groups = append(groups, id) - } - - if len(groups) > 0 { - perm.SourceGroups = make([]ec2.UserSecurityGroup, len(groups)) - for i, name := range groups { - ownerId, id := "", name - if items := strings.Split(id, "/"); len(items) > 1 { - ownerId, id = items[0], items[1] - } - - perm.SourceGroups[i] = ec2.UserSecurityGroup{ - Id: id, - OwnerId: ownerId, - } - } - } - - if raw, ok := m["cidr_blocks"]; ok { - list := raw.([]interface{}) - perm.SourceIPs = make([]string, len(list)) - for i, v := range list { - perm.SourceIPs[i] = v.(string) - } - } - - perms[i] = perm - } - - return perms -} - -// Takes the result of flatmap.Expand for an array of ingress/egress -// security group rules and returns EC2 API compatible objects -func expandIPPermsSDK(id string, configured []interface{}) []awsEC2.IPPermission { +func expandIPPerms(id string, configured []interface{}) []awsEC2.IPPermission { perms := make([]awsEC2.IPPermission, len(configured)) for i, mRaw := range configured { var perm awsEC2.IPPermission @@ -164,31 +112,6 @@ func expandParameters(configured []interface{}) ([]rds.Parameter, error) { return parameters, nil } -// Flattens an array of ipPerms into a list of primitives that -// flatmap.Flatten() can handle -func flattenIPPerms(list []ec2.IPPerm) []map[string]interface{} { - result := make([]map[string]interface{}, 0, len(list)) - - for _, perm := range list { - n := make(map[string]interface{}) - n["from_port"] = perm.FromPort - n["protocol"] = perm.Protocol - n["to_port"] = perm.ToPort - - if len(perm.SourceIPs) > 0 { - n["cidr_blocks"] = perm.SourceIPs - } - - if v := flattenSecurityGroups(perm.SourceGroups); len(v) > 0 { - n["security_groups"] = v - } - - result = append(result, n) - } - - return result -} - // Flattens a health check into something that flatmap.Flatten() // can handle func flattenHealthCheck(check *elb.HealthCheck) []map[string]interface{} { diff --git a/builtin/providers/aws/structure_test.go b/builtin/providers/aws/structure_test.go index f3a8bcc72..fdee02585 100644 --- a/builtin/providers/aws/structure_test.go +++ b/builtin/providers/aws/structure_test.go @@ -1,16 +1,17 @@ package aws import ( + "log" "reflect" "testing" "github.com/hashicorp/aws-sdk-go/aws" + awsEC2 "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/aws-sdk-go/gen/elb" "github.com/hashicorp/aws-sdk-go/gen/rds" "github.com/hashicorp/terraform/flatmap" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - "github.com/mitchellh/goamz/ec2" ) // Returns test configuration @@ -61,120 +62,60 @@ func TestExpandIPPerms(t *testing.T) { } perms := expandIPPerms("foo", expanded) - expected := []ec2.IPPerm{ - ec2.IPPerm{ - Protocol: "icmp", - FromPort: 1, - ToPort: -1, - SourceIPs: []string{"0.0.0.0/0"}, - SourceGroups: []ec2.UserSecurityGroup{ - ec2.UserSecurityGroup{ - OwnerId: "foo", - Id: "sg-22222", + log.Printf("wtf is perms:\n%#v", perms) + + expected := []awsEC2.IPPermission{ + awsEC2.IPPermission{ + IPProtocol: aws.String("icmp"), + FromPort: aws.Integer(1), + ToPort: aws.Integer(-1), + IPRanges: []awsEC2.IPRange{awsEC2.IPRange{aws.String("0.0.0.0/0")}}, + UserIDGroupPairs: []awsEC2.UserIDGroupPair{ + awsEC2.UserIDGroupPair{ + UserID: aws.String("foo"), + GroupID: aws.String("sg-22222"), }, - ec2.UserSecurityGroup{ - Id: "sg-11111", + awsEC2.UserIDGroupPair{ + GroupID: aws.String("sg-22222"), }, }, }, - ec2.IPPerm{ - Protocol: "icmp", - FromPort: 1, - ToPort: -1, - SourceGroups: []ec2.UserSecurityGroup{ - ec2.UserSecurityGroup{ - Id: "foo", + awsEC2.IPPermission{ + IPProtocol: aws.String("icmp"), + FromPort: aws.Integer(1), + ToPort: aws.Integer(-1), + UserIDGroupPairs: []awsEC2.UserIDGroupPair{ + awsEC2.UserIDGroupPair{ + UserID: aws.String("foo"), }, }, }, } - if !reflect.DeepEqual(perms, expected) { + exp := expected[0] + perm := perms[0] + + if *exp.FromPort != *perm.FromPort { t.Fatalf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", - perms[0], - expected) + *perm.FromPort, + *exp.FromPort) } -} - -func TestFlattenIPPerms(t *testing.T) { - cases := []struct { - Input []ec2.IPPerm - Output []map[string]interface{} - }{ - { - Input: []ec2.IPPerm{ - ec2.IPPerm{ - Protocol: "icmp", - FromPort: 1, - ToPort: -1, - SourceIPs: []string{"0.0.0.0/0"}, - SourceGroups: []ec2.UserSecurityGroup{ - ec2.UserSecurityGroup{ - Id: "sg-11111", - }, - }, - }, - }, - - Output: []map[string]interface{}{ - map[string]interface{}{ - "protocol": "icmp", - "from_port": 1, - "to_port": -1, - "cidr_blocks": []string{"0.0.0.0/0"}, - "security_groups": []string{"sg-11111"}, - }, - }, - }, - - { - Input: []ec2.IPPerm{ - ec2.IPPerm{ - Protocol: "icmp", - FromPort: 1, - ToPort: -1, - SourceIPs: []string{"0.0.0.0/0"}, - SourceGroups: nil, - }, - }, - - Output: []map[string]interface{}{ - map[string]interface{}{ - "protocol": "icmp", - "from_port": 1, - "to_port": -1, - "cidr_blocks": []string{"0.0.0.0/0"}, - }, - }, - }, - { - Input: []ec2.IPPerm{ - ec2.IPPerm{ - Protocol: "icmp", - FromPort: 1, - ToPort: -1, - SourceIPs: nil, - }, - }, - - Output: []map[string]interface{}{ - map[string]interface{}{ - "protocol": "icmp", - "from_port": 1, - "to_port": -1, - }, - }, - }, + if *exp.IPRanges[0].CIDRIP != *perm.IPRanges[0].CIDRIP { + t.Fatalf( + "Got:\n\n%#v\n\nExpected:\n\n%#v\n", + *perm.IPRanges[0].CIDRIP, + *exp.IPRanges[0].CIDRIP) } - for _, tc := range cases { - output := flattenIPPerms(tc.Input) - if !reflect.DeepEqual(output, tc.Output) { - t.Fatalf("Input:\n\n%#v\n\nOutput:\n\n%#v", tc.Input, output) - } + if *exp.UserIDGroupPairs[0].UserID != *perm.UserIDGroupPairs[0].UserID { + t.Fatalf( + "Got:\n\n%#v\n\nExpected:\n\n%#v\n", + *perm.UserIDGroupPairs[0].UserID, + *exp.UserIDGroupPairs[0].UserID) } + } func TestExpandListeners(t *testing.T) { From b038e5f720e4f740a53af29d6ca1c17b61ec3cb8 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Mon, 9 Mar 2015 17:11:30 -0500 Subject: [PATCH 16/20] provider/aws: Convert AWS Route Table Association to aws-sdk-go --- .../resource_aws_route_table_association.go | 43 +++++++++++-------- ...source_aws_route_table_association_test.go | 21 +++++---- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/builtin/providers/aws/resource_aws_route_table_association.go b/builtin/providers/aws/resource_aws_route_table_association.go index 4b39a79b7..3a566a56b 100644 --- a/builtin/providers/aws/resource_aws_route_table_association.go +++ b/builtin/providers/aws/resource_aws_route_table_association.go @@ -4,9 +4,10 @@ import ( "fmt" "log" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/mitchellh/goamz/ec2" ) func resourceAwsRouteTableAssociation() *schema.Resource { @@ -32,30 +33,31 @@ func resourceAwsRouteTableAssociation() *schema.Resource { } func resourceAwsRouteTableAssociationCreate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn log.Printf( "[INFO] Creating route table association: %s => %s", d.Get("subnet_id").(string), d.Get("route_table_id").(string)) - resp, err := ec2conn.AssociateRouteTable( - d.Get("route_table_id").(string), - d.Get("subnet_id").(string)) + resp, err := ec2conn.AssociateRouteTable(&ec2.AssociateRouteTableRequest{ + RouteTableID: aws.String(d.Get("route_table_id").(string)), + SubnetID: aws.String(d.Get("subnet_id").(string)), + }) if err != nil { return err } // Set the ID and return - d.SetId(resp.AssociationId) + d.SetId(*resp.AssociationID) log.Printf("[INFO] Association ID: %s", d.Id()) return nil } func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn // Get the routing table that this association belongs to rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc( @@ -71,9 +73,9 @@ func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface // Inspect that the association exists found := false for _, a := range rt.Associations { - if a.AssociationId == d.Id() { + if *a.RouteTableAssociationID == d.Id() { found = true - d.Set("subnet_id", a.SubnetId) + d.Set("subnet_id", *a.SubnetID) break } } @@ -87,19 +89,21 @@ func resourceAwsRouteTableAssociationRead(d *schema.ResourceData, meta interface } func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn log.Printf( "[INFO] Creating route table association: %s => %s", d.Get("subnet_id").(string), d.Get("route_table_id").(string)) - resp, err := ec2conn.ReassociateRouteTable( - d.Id(), - d.Get("route_table_id").(string)) + req := &ec2.ReplaceRouteTableAssociationRequest{ + AssociationID: aws.String(d.Id()), + RouteTableID: aws.String(d.Get("route_table_id").(string)), + } + resp, err := ec2conn.ReplaceRouteTableAssociation(req) if err != nil { - ec2err, ok := err.(*ec2.Error) + ec2err, ok := err.(aws.APIError) if ok && ec2err.Code == "InvalidAssociationID.NotFound" { // Not found, so just create a new one return resourceAwsRouteTableAssociationCreate(d, meta) @@ -109,18 +113,21 @@ func resourceAwsRouteTableAssociationUpdate(d *schema.ResourceData, meta interfa } // Update the ID - d.SetId(resp.AssociationId) + d.SetId(*resp.NewAssociationID) log.Printf("[INFO] Association ID: %s", d.Id()) return nil } func resourceAwsRouteTableAssociationDelete(d *schema.ResourceData, meta interface{}) error { - ec2conn := meta.(*AWSClient).ec2conn + ec2conn := meta.(*AWSClient).awsEC2conn log.Printf("[INFO] Deleting route table association: %s", d.Id()) - if _, err := ec2conn.DisassociateRouteTable(d.Id()); err != nil { - ec2err, ok := err.(*ec2.Error) + err := ec2conn.DisassociateRouteTable(&ec2.DisassociateRouteTableRequest{ + AssociationID: aws.String(d.Id()), + }) + if err != nil { + ec2err, ok := err.(aws.APIError) if ok && ec2err.Code == "InvalidAssociationID.NotFound" { return nil } diff --git a/builtin/providers/aws/resource_aws_route_table_association_test.go b/builtin/providers/aws/resource_aws_route_table_association_test.go index 079fb41f8..e0a591be4 100644 --- a/builtin/providers/aws/resource_aws_route_table_association_test.go +++ b/builtin/providers/aws/resource_aws_route_table_association_test.go @@ -4,9 +4,10 @@ import ( "fmt" "testing" + "github.com/hashicorp/aws-sdk-go/aws" + "github.com/hashicorp/aws-sdk-go/gen/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/mitchellh/goamz/ec2" ) func TestAccAWSRouteTableAssociation(t *testing.T) { @@ -37,7 +38,7 @@ func TestAccAWSRouteTableAssociation(t *testing.T) { } func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).ec2conn + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_route_table_association" { @@ -45,11 +46,12 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { } // Try to find the resource - resp, err := conn.DescribeRouteTables( - []string{rs.Primary.Attributes["route_table_Id"]}, ec2.NewFilter()) + resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ + RouteTableIDs: []string{rs.Primary.Attributes["route_table_id"]}, + }) if err != nil { // Verify the error is what we want - ec2err, ok := err.(*ec2.Error) + ec2err, ok := err.(aws.APIError) if !ok { return err } @@ -62,7 +64,7 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { rt := resp.RouteTables[0] if len(rt.Associations) > 0 { return fmt.Errorf( - "route table %s has associations", rt.RouteTableId) + "route table %s has associations", rt.RouteTableID) } } @@ -81,9 +83,10 @@ func testAccCheckRouteTableAssociationExists(n string, v *ec2.RouteTable) resour return fmt.Errorf("No ID is set") } - conn := testAccProvider.Meta().(*AWSClient).ec2conn - resp, err := conn.DescribeRouteTables( - []string{rs.Primary.Attributes["route_table_id"]}, ec2.NewFilter()) + conn := testAccProvider.Meta().(*AWSClient).awsEC2conn + resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ + RouteTableIDs: []string{rs.Primary.Attributes["route_table_id"]}, + }) if err != nil { return err } From 3c3b7d51a27d742b4e1ffe0f3bc44a8f98c0ec90 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 16:52:09 -0500 Subject: [PATCH 17/20] remove duplicated function --- .../providers/aws/resource_aws_route_table.go | 12 ++++----- .../resource_aws_route_table_association.go | 27 ------------------- 2 files changed, 6 insertions(+), 33 deletions(-) diff --git a/builtin/providers/aws/resource_aws_route_table.go b/builtin/providers/aws/resource_aws_route_table.go index 76bcd17a2..0290d053f 100644 --- a/builtin/providers/aws/resource_aws_route_table.go +++ b/builtin/providers/aws/resource_aws_route_table.go @@ -87,7 +87,7 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error stateConf := &resource.StateChangeConf{ Pending: []string{"pending"}, Target: "ready", - Refresh: resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id()), + Refresh: resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id()), Timeout: 1 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { @@ -102,7 +102,7 @@ func resourceAwsRouteTableCreate(d *schema.ResourceData, meta interface{}) error func resourceAwsRouteTableRead(d *schema.ResourceData, meta interface{}) error { ec2conn := meta.(*AWSClient).awsEC2conn - rtRaw, _, err := resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id())() + rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())() if err != nil { return err } @@ -217,7 +217,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error // First request the routing table since we'll have to disassociate // all the subnets first. - rtRaw, _, err := resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id())() + rtRaw, _, err := resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id())() if err != nil { return err } @@ -259,7 +259,7 @@ func resourceAwsRouteTableDelete(d *schema.ResourceData, meta interface{}) error stateConf := &resource.StateChangeConf{ Pending: []string{"ready"}, Target: "", - Refresh: resourceAwsRouteTableStateRefreshFuncSDK(ec2conn, d.Id()), + Refresh: resourceAwsRouteTableStateRefreshFunc(ec2conn, d.Id()), Timeout: 1 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { @@ -291,9 +291,9 @@ func resourceAwsRouteTableHash(v interface{}) int { return hashcode.String(buf.String()) } -// resourceAwsRouteTableStateRefreshFuncSDK returns a resource.StateRefreshFunc that is used to watch +// resourceAwsRouteTableStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // a RouteTable. -func resourceAwsRouteTableStateRefreshFuncSDK(conn *ec2.EC2, id string) resource.StateRefreshFunc { +func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesRequest{ RouteTableIDs: []string{id}, diff --git a/builtin/providers/aws/resource_aws_route_table_association.go b/builtin/providers/aws/resource_aws_route_table_association.go index 3a566a56b..a9a614f7f 100644 --- a/builtin/providers/aws/resource_aws_route_table_association.go +++ b/builtin/providers/aws/resource_aws_route_table_association.go @@ -6,7 +6,6 @@ import ( "github.com/hashicorp/aws-sdk-go/aws" "github.com/hashicorp/aws-sdk-go/gen/ec2" - "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -137,29 +136,3 @@ func resourceAwsRouteTableAssociationDelete(d *schema.ResourceData, meta interfa return nil } - -// TODO: remove this method when converting to aws-sdk-go -// resourceAwsRouteTableStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch -// a RouteTable. -func resourceAwsRouteTableStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { - return func() (interface{}, string, error) { - resp, err := conn.DescribeRouteTables([]string{id}, ec2.NewFilter()) - if err != nil { - if ec2err, ok := err.(*ec2.Error); ok && ec2err.Code == "InvalidRouteTableID.NotFound" { - resp = nil - } else { - log.Printf("Error on RouteTableStateRefresh: %s", err) - return nil, "", err - } - } - - if resp == nil { - // Sometimes AWS just has consistency issues and doesn't see - // our instance yet. Return an empty state. - return nil, "", nil - } - - rt := &resp.RouteTables[0] - return rt, "ready", nil - } -} From 314453abe5dd68fdd2b4e6324345bdbcd9e1faa0 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Tue, 10 Mar 2015 16:57:43 -0500 Subject: [PATCH 18/20] fix nit-pick from go vet --- .../providers/aws/resource_aws_route_table_association_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/aws/resource_aws_route_table_association_test.go b/builtin/providers/aws/resource_aws_route_table_association_test.go index e0a591be4..8c4246aba 100644 --- a/builtin/providers/aws/resource_aws_route_table_association_test.go +++ b/builtin/providers/aws/resource_aws_route_table_association_test.go @@ -64,7 +64,7 @@ func testAccCheckRouteTableAssociationDestroy(s *terraform.State) error { rt := resp.RouteTables[0] if len(rt.Associations) > 0 { return fmt.Errorf( - "route table %s has associations", rt.RouteTableID) + "route table %s has associations", *rt.RouteTableID) } } From f5b4f3fe09da5620eadd1abc06d9f8856013b990 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 11 Mar 2015 08:31:58 +0100 Subject: [PATCH 19/20] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5000e028..8470f90b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,8 @@ BUG FIXES: "resource.0" would ignore the latter completely. [GH-1086] * providers/aws: manually deleted VPC removes it from the state * providers/aws: `source_dest_check` regression fixed (now works). [GH-1020] - * providers/aws: Longer wait times for DB instances + * providers/aws: Longer wait times for DB instances. + * providers/aws: Longer wait times for route53 records (30 mins). [GH-1164] * providers/digitalocean: Waits until droplet is ready to be destroyed [GH-1057] * providers/digitalocean: More lenient about 404's while waiting [GH-1062] * providers/google: Network data in state was not being stored. [GH-1095] From 902ca25f36032dd08e8b73b95499e00b63a372a6 Mon Sep 17 00:00:00 2001 From: Clint Shryock Date: Wed, 11 Mar 2015 08:30:43 -0500 Subject: [PATCH 20/20] Code cleanup --- builtin/providers/aws/resource_aws_security_group.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/builtin/providers/aws/resource_aws_security_group.go b/builtin/providers/aws/resource_aws_security_group.go index 4a7153cc7..b7addd9aa 100644 --- a/builtin/providers/aws/resource_aws_security_group.go +++ b/builtin/providers/aws/resource_aws_security_group.go @@ -320,15 +320,11 @@ func resourceAwsSecurityGroupIPPermGather(d *schema.ResourceData, permissions [] ruleMap := make(map[string]map[string]interface{}) for _, perm := range permissions { var fromPort, toPort int - if perm.FromPort == nil { - fromPort = 0 - } else { - fromPort = *perm.FromPort + if v := perm.FromPort; v != nil { + fromPort = *v } - if perm.ToPort == nil { - toPort = 0 - } else { - toPort = *perm.ToPort + if v := perm.ToPort; v != nil { + toPort = *v } k := fmt.Sprintf("%s-%d-%d", *perm.IPProtocol, fromPort, toPort)